last
diff --git a/src/main/java/de/ids_mannheim/korap/config/JWTSigner.java b/src/main/java/de/ids_mannheim/korap/config/JWTSigner.java
index 30f8e2f..d959604 100644
--- a/src/main/java/de/ids_mannheim/korap/config/JWTSigner.java
+++ b/src/main/java/de/ids_mannheim/korap/config/JWTSigner.java
@@ -41,25 +41,25 @@
         this(secret, new URL(issuer), 72 * 60 * 60);
     }
 
-    public SignedJWT createJWT(User user, Map<String, String> attr) {
+    public SignedJWT createJWT(User user, Map<String, Object> attr) {
         return signContent(user, attr, defaultttl);
     }
 
-    public SignedJWT signContent(User user, Map<String, String> attr, int ttl) {
+    public SignedJWT signContent(User user, Map<String, Object> attr, int ttl) {
         String scopes;
 
         JWTClaimsSet cs = new JWTClaimsSet();
         cs.setIssuerClaim(this.issuer.toString());
 
-        if ((scopes = attr.get(Attributes.SCOPES)) != null) {
-            Scopes claims = Scopes.mapScopes(scopes, user.getDetails());
+        if ((scopes = (String) attr.get(Attributes.SCOPES)) != null) {
+            Scopes claims = Scopes.mapScopes(scopes, attr);
             cs.setCustomClaims(claims.toMap());
         }
 
         cs.setSubjectClaim(user.getUsername());
         if (attr.get(Attributes.CLIENT_ID) != null)
             cs.setAudienceClaim(
-                    new String[] { attr.get(Attributes.CLIENT_ID) });
+                    new String[] { (String) attr.get(Attributes.CLIENT_ID) });
         cs.setExpirationTimeClaim(
                 TimeUtils.getNow().plusSeconds(ttl).getMillis());
         SignedJWT signedJWT = new SignedJWT(new JWSHeader(JWSAlgorithm.HS256),
diff --git a/src/main/java/de/ids_mannheim/korap/config/KustvaktClassLoader.java b/src/main/java/de/ids_mannheim/korap/config/KustvaktClassLoader.java
index c175824..f63a023 100644
--- a/src/main/java/de/ids_mannheim/korap/config/KustvaktClassLoader.java
+++ b/src/main/java/de/ids_mannheim/korap/config/KustvaktClassLoader.java
@@ -38,6 +38,8 @@
         return reflections.getTypesAnnotatedWith(annotation);
     }
 
+
+
     @Deprecated
     public static void registerResourceClasses() {
         PersistenceClient cl = BeanConfiguration.getBeans()
diff --git a/src/main/java/de/ids_mannheim/korap/config/Scopes.java b/src/main/java/de/ids_mannheim/korap/config/Scopes.java
index 63a3f07..cce49e8 100644
--- a/src/main/java/de/ids_mannheim/korap/config/Scopes.java
+++ b/src/main/java/de/ids_mannheim/korap/config/Scopes.java
@@ -1,7 +1,6 @@
 package de.ids_mannheim.korap.config;
 
 import de.ids_mannheim.korap.user.Attributes;
-import de.ids_mannheim.korap.user.UserDetails;
 import de.ids_mannheim.korap.utils.JsonUtils;
 
 import java.util.ArrayList;
@@ -54,18 +53,17 @@
         return s.toArray(new Scope[s.size()]);
     }
 
-    public static Scopes mapScopes(String scopes, UserDetails details) {
+    public static Scopes mapScopes(String scopes, Map<String, Object> details) {
         Scopes m = new Scopes();
-        Map<String, Object> det = details.toMap();
         if (scopes != null && !scopes.isEmpty()) {
             Scope[] scopearr = mapScopes(scopes);
             for (Scope s : scopearr) {
-                Object v = det.get(s.toString());
+                Object v = details.get(s.toString());
                 if (v != null)
                     m._values.put(s.toString(), v);
             }
             if (scopes.contains(Scope.profile.toString()))
-                m._values.putAll(Scopes.getProfileScopes(det)._values);
+                m._values.putAll(Scopes.getProfileScopes(details)._values);
             m._values.put(Attributes.SCOPES, scopes);
         }
         return m;
diff --git a/src/main/java/de/ids_mannheim/korap/exceptions/StatusCodes.java b/src/main/java/de/ids_mannheim/korap/exceptions/StatusCodes.java
index c44888f..34aa013 100644
--- a/src/main/java/de/ids_mannheim/korap/exceptions/StatusCodes.java
+++ b/src/main/java/de/ids_mannheim/korap/exceptions/StatusCodes.java
@@ -56,7 +56,7 @@
     public static final Integer UNSUPPORTED_CORPUS = 404;
     public static final Integer UNSUPPORTED_LAYER = 405;
     // make a distinction between no and invalid vc?
-    public static final Integer UNSUPPORTED_VIRTUALCOLLECTION = 406;
+    public static final Integer UNSUPPORTED_COLLECTION = 406;
     public static final Integer CORPUS_REWRITE = 407;
     public static final Integer FOUNDRY_REWRITE = 408;
     public static final Integer FOUNDRY_INJECTION = 409;
diff --git a/src/main/java/de/ids_mannheim/korap/handlers/EntityDao.java b/src/main/java/de/ids_mannheim/korap/handlers/EntityDao.java
index 38e0834..e87b62d 100644
--- a/src/main/java/de/ids_mannheim/korap/handlers/EntityDao.java
+++ b/src/main/java/de/ids_mannheim/korap/handlers/EntityDao.java
@@ -8,23 +8,22 @@
 import de.ids_mannheim.korap.exceptions.dbException;
 import de.ids_mannheim.korap.interfaces.db.EntityHandlerIface;
 import de.ids_mannheim.korap.interfaces.db.PersistenceClient;
-import de.ids_mannheim.korap.user.*;
+import de.ids_mannheim.korap.user.DemoUser;
+import de.ids_mannheim.korap.user.KorAPUser;
+import de.ids_mannheim.korap.user.ShibUser;
+import de.ids_mannheim.korap.user.User;
 import de.ids_mannheim.korap.utils.BooleanUtils;
 import de.ids_mannheim.korap.utils.TimeUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.dao.DataAccessException;
 import org.springframework.dao.EmptyResultDataAccessException;
-import org.springframework.jdbc.core.RowMapper;
-import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
 import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
 import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
 import org.springframework.jdbc.support.GeneratedKeyHolder;
 import org.springframework.jdbc.support.KeyHolder;
 
 import java.sql.Date;
-import java.sql.ResultSet;
-import java.sql.SQLException;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
@@ -43,185 +42,6 @@
         this.jdbcTemplate = (NamedParameterJdbcTemplate) client.getSource();
     }
 
-    @Override
-    public UserSettings getUserSettings(Integer userid)
-            throws KustvaktException {
-        //        TransactionDefinition def = new DefaultTransactionDefinition();
-        //        TransactionStatus status = transactionManager.getTransaction(def);
-
-        MapSqlParameterSource np = new MapSqlParameterSource();
-        np.addValue("us", userid);
-        final String sql =
-                "SELECT user.* FROM user_settings as user inner join korap_users as a "
-                        + "on a.id=user.user_id WHERE user.user_id=:us";
-        try {
-            Map s = this.jdbcTemplate.queryForMap(sql, np);
-            return UserSettings.fromObjectMap(s);
-        }catch (EmptyResultDataAccessException ex) {
-            return new UserSettings();
-        }catch (DataAccessException e) {
-            jlog.error("Could not retrieve user settings for user: " + userid,
-                    e);
-            throw new dbException(userid, "user_settings",
-                    StatusCodes.DB_GET_FAILED, userid.toString());
-        }
-    }
-
-    @Override
-    public int updateSettings(UserSettings settings) throws KustvaktException {
-        final String sql =
-                "UPDATE user_settings SET fileNameForExport=:fileNameForExport,"
-                        +
-                        "leftContextItemForExport=:leftContextItemForExport," +
-                        "leftContextSizeForExport=:leftContextSizeForExport,locale=:locale,leftContextItem=:leftContextItem,"
-                        +
-                        "leftContextSize=:leftContextSize," +
-                        "rightContextItem=:rightContextItem,rightContextItemForExport=:rightContextItemForExport,"
-                        +
-                        "rightContextSize=:rightContextSize," +
-                        "POSFoundry=:defaultPOSfoundry, lemmaFoundry=:defaultLemmafoundry, constFoundry=:defaultConstfoundry, "
-                        +
-                        "relFoundry=:defaultRelfoundry, " +
-                        "rightContextSizeForExport=:rightContextSizeForExport,selectedCollection=:selectedCollection,queryLanguage=:queryLanguage,"
-                        +
-                        "pageLength=:pageLength,metadataQueryExpertModus=:metadataQueryExpertModus,collectData=:collectData "
-                        +
-                        "WHERE user_id=:userID";
-        try {
-            return this.jdbcTemplate
-                    .update(sql, new BeanPropertySqlParameterSource(settings));
-        }catch (DataAccessException e) {
-            jlog.error("Could not update user settings for user: " + settings
-                    .getUserID(), e);
-            throw new dbException(settings.getUserID(), "user_settings",
-                    StatusCodes.DB_UPDATE_FAILED, settings.toString());
-        }
-    }
-
-    /**
-     * @param settings
-     * @throws KustvaktException
-     */
-
-    private void createSettings(UserSettings settings)
-            throws KustvaktException {
-        final String sql =
-                "INSERT INTO user_settings (user_id, fileNameForExport,leftContextItemForExport,"
-                        +
-                        "leftContextSizeForExport,locale,leftContextItem,leftContextSize,"
-                        +
-                        "rightContextItem,rightContextItemForExport,rightContextSize,"
-                        +
-                        "rightContextSizeForExport,selectedCollection,queryLanguage,"
-                        +
-                        "pageLength,metadataQueryExpertModus, POSFoundry, lemmaFoundry, constFoundry, relFoundry, collectData) "
-                        +
-                        "VALUES (:userID, :fileNameForExport, :leftContextItemForExport, "
-                        +
-                        ":leftContextSizeForExport, :locale, :leftContextItem, :leftContextSize, "
-                        +
-                        ":rightContextItem,:rightContextItemForExport, :rightContextSize, "
-                        +
-                        ":rightContextSizeForExport, :selectedCollection, :queryLanguage, "
-                        +
-                        ":pageLength, :metadataQueryExpertModus, :defaultPOSfoundry, "
-                        +
-                        ":defaultLemmafoundry, :defaultConstfoundry, :defaultRelfoundry, :collectData);";
-
-        try {
-            if (settings == null)
-                throw new KustvaktException(StatusCodes.MISSING_ARGUMENTS,
-                        "no settings provided", "user settings");
-            this.jdbcTemplate
-                    .update(sql, new BeanPropertySqlParameterSource(settings));
-        }catch (DataAccessException e) {
-            jlog.error("Could not create user settings for user: " + settings
-                    .getUserID(), e);
-            throw new dbException(settings.getUserID(), "userSettings",
-                    StatusCodes.DB_INSERT_FAILED, settings.toString());
-        }
-    }
-
-    @Override
-    public UserDetails getUserDetails(Integer userid) throws KustvaktException {
-        final String sql = "SELECT us.* FROM user_details as us inner join korap_users as ku on ku.id=us.user_id WHERE us.user_id=:user";
-        MapSqlParameterSource np = new MapSqlParameterSource();
-        np.addValue("user", userid);
-
-        try {
-            return this.jdbcTemplate
-                    .queryForObject(sql, np, new RowMapper<UserDetails>() {
-                        @Override
-                        public UserDetails mapRow(ResultSet rs, int i)
-                                throws SQLException {
-                            UserDetails d = new UserDetails();
-                            d.setUserID(rs.getInt("user_id"));
-                            d.setAddress(rs.getString("address"));
-                            d.setCountry(rs.getString("country"));
-                            d.setEmail(rs.getString("email"));
-                            d.setFirstName(rs.getString("firstName"));
-                            d.setLastName(rs.getString("lastName"));
-                            d.setGender(rs.getString("gender"));
-                            d.setInstitution(rs.getString("institution"));
-                            d.setPhone(rs.getString("phone"));
-                            d.setPrivateUsage(rs.getBoolean("privateUsage"));
-                            return d;
-                        }
-                    });
-        }catch (EmptyResultDataAccessException ex) {
-            //todo: create audit record?
-            return null;
-        }catch (DataAccessException e) {
-            jlog.error("Could not retrieve user details for user: " + userid,
-                    e);
-            throw new dbException(userid, "userDetails",
-                    StatusCodes.DB_GET_FAILED, userid.toString());
-        }
-    }
-
-    @Override
-    public int updateUserDetails(UserDetails details) throws KustvaktException {
-        final String up =
-                "UPDATE user_details SET firstName=:firstName, lastName=:lastName, "
-                        +
-                        "gender=:gender, phone=:phone, institution=:institution, "
-                        +
-                        "email=:email, address=:address, country=:country, privateUsage=:privateUsage "
-                        +
-                        "WHERE user_id=:userID;";
-        try {
-            return this.jdbcTemplate
-                    .update(up, new BeanPropertySqlParameterSource(details));
-        }catch (DataAccessException e) {
-            jlog.error("Could not retrieve user details for user: " + details
-                    .getUserID(), e);
-            throw new dbException(details.getUserID(), "userDetails",
-                    StatusCodes.DB_UPDATE_FAILED, details.toString());
-        }
-    }
-
-    private void createUserDetails(UserDetails details)
-            throws KustvaktException {
-        final String up =
-                "INSERT INTO user_details (user_id, firstName, lastName, gender, phone, institution, "
-                        +
-                        "email, address, country, privateUsage) VALUES (:userID, :firstName, :lastName, :gender, "
-                        +
-                        ":phone, :institution, :email, :address, :country, :privateUsage);";
-        try {
-            if (details == null)
-                throw new KustvaktException(StatusCodes.MISSING_ARGUMENTS,
-                        "no details provided", "user details");
-            this.jdbcTemplate
-                    .update(up, new BeanPropertySqlParameterSource(details));
-        }catch (DataAccessException e) {
-            jlog.error("Could not create user details for user: " + details
-                    .getUserID(), e);
-            throw new dbException(details.getUserID(), "userDetails",
-                    StatusCodes.DB_INSERT_FAILED, details.toString());
-        }
-    }
-
     // usersettings are fetched plus basic account info, no details, since i rarely use them anyway!
     @Override
     public User getAccount(String username) throws KustvaktException {
@@ -376,14 +196,6 @@
             int r = this.jdbcTemplate
                     .update(query, np, holder, new String[] { "id" });
             user.setId(holder.getKey().intValue());
-
-            if (user.getDetails() == null)
-                user.setDetails(new UserDetails());
-            if (user.getSettings() == null)
-                user.setSettings(new UserSettings());
-
-            this.createUserDetails(user.getDetails());
-            this.createSettings(user.getSettings());
             return r;
         }catch (DataAccessException e) {
             jlog.error("Could not create user account with username: {}",
diff --git a/src/main/java/de/ids_mannheim/korap/interfaces/AuthenticationIface.java b/src/main/java/de/ids_mannheim/korap/interfaces/AuthenticationIface.java
index 13f29f6..82d6737 100644
--- a/src/main/java/de/ids_mannheim/korap/interfaces/AuthenticationIface.java
+++ b/src/main/java/de/ids_mannheim/korap/interfaces/AuthenticationIface.java
@@ -11,7 +11,7 @@
     TokenContext getUserStatus(String authToken) throws
             KustvaktException;
 
-    TokenContext createUserSession(User user, Map<String, String> attr)
+    TokenContext createUserSession(User user, Map<String, Object> attr)
             throws KustvaktException;
 
     void removeUserSession(String token) throws KustvaktException;
diff --git a/src/main/java/de/ids_mannheim/korap/interfaces/AuthenticationManagerIface.java b/src/main/java/de/ids_mannheim/korap/interfaces/AuthenticationManagerIface.java
index ccc79d8..8204a4f 100644
--- a/src/main/java/de/ids_mannheim/korap/interfaces/AuthenticationManagerIface.java
+++ b/src/main/java/de/ids_mannheim/korap/interfaces/AuthenticationManagerIface.java
@@ -1,10 +1,7 @@
 package de.ids_mannheim.korap.interfaces;
 
 import de.ids_mannheim.korap.exceptions.KustvaktException;
-import de.ids_mannheim.korap.user.TokenContext;
-import de.ids_mannheim.korap.user.User;
-import de.ids_mannheim.korap.user.UserDetails;
-import de.ids_mannheim.korap.user.UserSettings;
+import de.ids_mannheim.korap.user.*;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -43,35 +40,29 @@
     public abstract User getUser(String username) throws KustvaktException;
 
     public abstract User authenticate(int type, String username,
-            String password, Map<String, String> attributes)
+            String password, Map<String, Object> attributes)
             throws KustvaktException;
 
     public abstract TokenContext createTokenContext(User user,
-            Map<String, String> attr, String provider_key)
+            Map<String, Object> attr, String provider_key)
             throws KustvaktException;
 
     public abstract void logout(TokenContext context) throws KustvaktException;
 
     public abstract void lockAccount(User user) throws KustvaktException;
 
-    public abstract User createUserAccount(Map attributes,
+    public abstract User createUserAccount(Map<String, Object> attributes,
             boolean confirmation_required) throws KustvaktException;
 
-//    public abstract boolean updateAccount(User user) throws KustvaktException;
+    //    public abstract boolean updateAccount(User user) throws KustvaktException;
 
     public abstract boolean deleteAccount(User user) throws KustvaktException;
 
-    public abstract UserDetails getUserDetails(User user)
-            throws KustvaktException;
+    public abstract <T extends Userdata> T getUserData(User user,
+            Class<T> clazz) throws KustvaktException;
 
-    public abstract UserSettings getUserSettings(User user)
-            throws KustvaktException;
+    public abstract void updateUserData(Userdata data) throws KustvaktException;
 
-    public abstract void updateUserDetails(User user, UserDetails details)
-            throws KustvaktException;
-
-    public abstract void updateUserSettings(User user, UserSettings settings)
-            throws KustvaktException;
 
     public abstract Object[] validateResetPasswordRequest(String username,
             String email) throws KustvaktException;
diff --git a/src/main/java/de/ids_mannheim/korap/interfaces/EncryptionIface.java b/src/main/java/de/ids_mannheim/korap/interfaces/EncryptionIface.java
index 3b035b4..ec31ed7 100644
--- a/src/main/java/de/ids_mannheim/korap/interfaces/EncryptionIface.java
+++ b/src/main/java/de/ids_mannheim/korap/interfaces/EncryptionIface.java
@@ -64,7 +64,7 @@
 
     public String encodeBase();
 
-    public Map validateMap(Map map) throws KustvaktException;
+    public Map<String, Object> validateMap(Map<String, Object> map) throws KustvaktException;
 
     public String validateEntry(String input, String type)
             throws KustvaktException;
diff --git a/src/main/java/de/ids_mannheim/korap/interfaces/db/EntityHandlerIface.java b/src/main/java/de/ids_mannheim/korap/interfaces/db/EntityHandlerIface.java
index f349f23..c83f60d 100644
--- a/src/main/java/de/ids_mannheim/korap/interfaces/db/EntityHandlerIface.java
+++ b/src/main/java/de/ids_mannheim/korap/interfaces/db/EntityHandlerIface.java
@@ -3,8 +3,6 @@
 import de.ids_mannheim.korap.exceptions.EmptyResultException;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.user.User;
-import de.ids_mannheim.korap.user.UserDetails;
-import de.ids_mannheim.korap.user.UserSettings;
 
 /**
  * User: hanl
@@ -12,22 +10,9 @@
  * Time: 11:04 AM
  */
 public interface EntityHandlerIface {
-    UserSettings getUserSettings(Integer userid) throws KustvaktException;
 
-    int updateSettings(UserSettings settings) throws KustvaktException;
-
-    UserDetails getUserDetails(Integer userid) throws KustvaktException;
-
-    int updateUserDetails(UserDetails details) throws KustvaktException;
-
-    //    List<UserQuery> getUserQueries(User user) throws KorAPException;
-
-    //    UserQuery getUserQuery(String id) throws KorAPException;
-
-    //    void updateUserQueries(User user, List<UserQuery> newOnes) throws KorAPException;
-
-    User getAccount(String username) throws
-            EmptyResultException, KustvaktException;
+    User getAccount(String username)
+            throws EmptyResultException, KustvaktException;
 
     int updateAccount(User user) throws KustvaktException;
 
@@ -35,8 +20,8 @@
 
     int deleteAccount(Integer userid) throws KustvaktException;
 
-    int resetPassphrase(String username, String uriToken,
-            String passphrase) throws KustvaktException;
+    int resetPassphrase(String username, String uriToken, String passphrase)
+            throws KustvaktException;
 
     int activateAccount(String username, String uriToken)
             throws KustvaktException;
diff --git a/src/main/java/de/ids_mannheim/korap/interfaces/db/ResourceOperationIface.java b/src/main/java/de/ids_mannheim/korap/interfaces/db/ResourceOperationIface.java
index cfa4c99..d35f924 100644
--- a/src/main/java/de/ids_mannheim/korap/interfaces/db/ResourceOperationIface.java
+++ b/src/main/java/de/ids_mannheim/korap/interfaces/db/ResourceOperationIface.java
@@ -11,6 +11,8 @@
 // todo: user instance only required for auditing pointcut operations
 public interface ResourceOperationIface<T extends KustvaktResource> {
 
+    // todo: remove and use type reference!
+    @Deprecated
     Class<T> getType();
 
     <T extends KustvaktResource> T findbyId(String id, User user)
diff --git a/src/main/java/de/ids_mannheim/korap/interfaces/defaults/KustvaktEncryption.java b/src/main/java/de/ids_mannheim/korap/interfaces/defaults/KustvaktEncryption.java
index 2a1cde8..dbd3649 100644
--- a/src/main/java/de/ids_mannheim/korap/interfaces/defaults/KustvaktEncryption.java
+++ b/src/main/java/de/ids_mannheim/korap/interfaces/defaults/KustvaktEncryption.java
@@ -283,7 +283,7 @@
 
     // todo: where applied?
     @Override
-    public Map validateMap(Map map) throws KustvaktException {
+    public Map<String, Object> validateMap(Map<String, Object> map) throws KustvaktException {
         Map<String, Object> safeMap = new HashMap<>();
         KustvaktMap kmap = new KustvaktMap(map);
 
diff --git a/src/main/java/de/ids_mannheim/korap/resource/rewrite/FoundryInject.java b/src/main/java/de/ids_mannheim/korap/resource/rewrite/FoundryInject.java
index eebc92c..e4a8e4b 100644
--- a/src/main/java/de/ids_mannheim/korap/resource/rewrite/FoundryInject.java
+++ b/src/main/java/de/ids_mannheim/korap/resource/rewrite/FoundryInject.java
@@ -16,8 +16,9 @@
     public JsonNode preProcess(KoralNode node, KustvaktConfiguration config,
             User user) {
         LayerMapper mapper;
+        // inject user settings from cache!
         if (user != null)
-            mapper = new LayerMapper(config, user.getSettings());
+            mapper = new LayerMapper(config, null);
         else
             mapper = new LayerMapper(config);
 
diff --git a/src/main/java/de/ids_mannheim/korap/resource/rewrite/RewriteHandler.java b/src/main/java/de/ids_mannheim/korap/resource/rewrite/RewriteHandler.java
index 4db050a..596941f 100644
--- a/src/main/java/de/ids_mannheim/korap/resource/rewrite/RewriteHandler.java
+++ b/src/main/java/de/ids_mannheim/korap/resource/rewrite/RewriteHandler.java
@@ -122,6 +122,7 @@
     }
 
     private JsonNode process(JsonNode root, User user, boolean post) {
+        jlog.debug("Running rewrite process on query {}", root);
         Iterator<Map.Entry<String, JsonNode>> it = root.fields();
         while (it.hasNext()) {
             Map.Entry<String, JsonNode> next = it.next();
diff --git a/src/main/java/de/ids_mannheim/korap/security/auth/APIAuthentication.java b/src/main/java/de/ids_mannheim/korap/security/auth/APIAuthentication.java
index d59e503..297a36e 100644
--- a/src/main/java/de/ids_mannheim/korap/security/auth/APIAuthentication.java
+++ b/src/main/java/de/ids_mannheim/korap/security/auth/APIAuthentication.java
@@ -58,7 +58,7 @@
     }
 
     @Override
-    public TokenContext createUserSession(User user, Map<String, String> attr)
+    public TokenContext createUserSession(User user, Map<String, Object> attr)
             throws KustvaktException {
         TokenContext c = new TokenContext();
         c.setUsername(user.getUsername());
diff --git a/src/main/java/de/ids_mannheim/korap/security/auth/BasicHttpAuth.java b/src/main/java/de/ids_mannheim/korap/security/auth/BasicHttpAuth.java
index 4470a30..e97ea53 100644
--- a/src/main/java/de/ids_mannheim/korap/security/auth/BasicHttpAuth.java
+++ b/src/main/java/de/ids_mannheim/korap/security/auth/BasicHttpAuth.java
@@ -74,7 +74,7 @@
 
     // not supported!
     @Override
-    public TokenContext createUserSession(User user, Map<String, String> attr)
+    public TokenContext createUserSession(User user, Map<String, Object> attr)
             throws KustvaktException {
         return null;
     }
diff --git a/src/main/java/de/ids_mannheim/korap/security/auth/KustvaktAuthenticationManager.java b/src/main/java/de/ids_mannheim/korap/security/auth/KustvaktAuthenticationManager.java
index d34f968..2eca9e0 100644
--- a/src/main/java/de/ids_mannheim/korap/security/auth/KustvaktAuthenticationManager.java
+++ b/src/main/java/de/ids_mannheim/korap/security/auth/KustvaktAuthenticationManager.java
@@ -12,7 +12,6 @@
 import de.ids_mannheim.korap.user.*;
 import de.ids_mannheim.korap.utils.StringUtils;
 import de.ids_mannheim.korap.utils.TimeUtils;
-import de.ids_mannheim.korap.web.utils.KustvaktMap;
 import net.sf.ehcache.Cache;
 import net.sf.ehcache.CacheManager;
 import net.sf.ehcache.Element;
@@ -109,7 +108,7 @@
         AuthenticationIface provider = getProvider(context.getTokenType(),
                 null);
         if (provider == null) {
-
+            //todo:
         }
 
         try {
@@ -128,8 +127,9 @@
      * @return User
      * @throws KustvaktException
      */
+    @Override
     public User authenticate(int type, String username, String password,
-            Map<String, String> attributes) throws KustvaktException {
+            Map<String, Object> attributes) throws KustvaktException {
         User user;
         switch (type) {
             case 1:
@@ -146,19 +146,21 @@
         return user;
     }
 
+    // todo: dont use annotations for caching
+    @Override
     @CachePut(value = "users", key = "#user.getUsername()")
-    public TokenContext createTokenContext(User user, Map<String, String> attr,
+    public TokenContext createTokenContext(User user, Map<String, Object> attr,
             String provider_key) throws KustvaktException {
         AuthenticationIface provider = getProvider(provider_key,
                 Attributes.API_AUTHENTICATION);
 
         if (attr.get(Attributes.SCOPES) != null)
-            this.getUserDetails(user);
+            this.getUserData(user, Userdetails2.class);
 
         TokenContext context = provider.createUserSession(user, attr);
         if (context == null)
             throw new KustvaktException(StatusCodes.NOT_SUPPORTED);
-        context.setUserAgent(attr.get(Attributes.USER_AGENT));
+        context.setUserAgent((String) attr.get(Attributes.USER_AGENT));
         context.setHostAddress(Attributes.HOST);
         return context;
     }
@@ -174,7 +176,7 @@
         return false;
     }
 
-    private User authenticateShib(Map<String, String> attributes)
+    private User authenticateShib(Map<String, Object> attributes)
             throws KustvaktException {
         // todo use persistent id, since eppn is not unique
         String eppn = (String) attributes.get(Attributes.EPPN);
@@ -195,8 +197,8 @@
 
     //todo: what if attributes null?
     private User authenticate(String username, String password,
-            Map<String, String> attr) throws KustvaktException {
-        Map<String, String> attributes = crypto.validateMap(attr);
+            Map<String, Object> attr) throws KustvaktException {
+        Map<String, Object> attributes = crypto.validateMap(attr);
         String safeUS;
         User unknown;
         // just to make sure that the plain password does not appear anywhere in the logs!
@@ -213,8 +215,6 @@
         else {
             try {
                 unknown = entHandler.getAccount(safeUS);
-                unknown.setSettings(
-                        entHandler.getUserSettings(unknown.getId()));
             }catch (EmptyResultException e) {
                 // mask exception to disable user guessing in possible attacks
                 throw new WrappedException(new KustvaktException(username,
@@ -458,11 +458,9 @@
      * @throws KustvaktException
      */
     //fixme: remove clientinfo object (not needed), use json representation to get stuff
-    public User createUserAccount(Map attributes, boolean confirmation_required)
-            throws KustvaktException {
-        KustvaktMap kmap = new KustvaktMap(attributes);
-
-        Map<String, String> safeMap = crypto.validateMap(attributes);
+    public User createUserAccount(Map<String, Object> attributes,
+            boolean confirmation_required) throws KustvaktException {
+        Map<String, Object> safeMap = crypto.validateMap(attributes);
         if (safeMap.get(Attributes.USERNAME) == null || ((String) safeMap
                 .get(Attributes.USERNAME)).isEmpty())
             throw new KustvaktException(StatusCodes.ILLEGAL_ARGUMENT,
@@ -473,10 +471,12 @@
                     StatusCodes.ILLEGAL_ARGUMENT, "password must be set",
                     "password");
 
-        String username = crypto.validateEntry(safeMap.get(Attributes.USERNAME),
-                Attributes.USERNAME);
-        String safePass = crypto.validateEntry(safeMap.get(Attributes.PASSWORD),
-                Attributes.PASSWORD);
+        String username = crypto
+                .validateEntry((String) safeMap.get(Attributes.USERNAME),
+                        Attributes.USERNAME);
+        String safePass = crypto
+                .validateEntry((String) safeMap.get(Attributes.PASSWORD),
+                        Attributes.PASSWORD);
         String hash;
         try {
             hash = crypto.produceSecureHash(safePass);
@@ -486,9 +486,6 @@
         }
 
         KorAPUser user = User.UserFactory.getUser(username);
-        UserDetails det = UserDetails.newDetailsIterator(safeMap);
-        user.setDetails(det);
-        user.setSettings(new UserSettings());
         if (confirmation_required) {
             user.setAccountLocked(true);
             URIParam param = new URIParam(crypto.createToken(),
@@ -498,6 +495,16 @@
         user.setPassword(hash);
         try {
             entHandler.createAccount(user);
+            Userdetails2 details = new Userdetails2(user.getId());
+            details.readDefaults(safeMap);
+            details.checkRequired();
+
+            UserSettings2 settings = new UserSettings2(user.getId());
+            settings.readDefaults(safeMap);
+            settings.checkRequired();
+
+            UserdataFactory.getDaoInstance(Userdetails2.class).store(details);
+            UserdataFactory.getDaoInstance(UserSettings2.class).store(settings);
         }catch (KustvaktException e) {
             throw new WrappedException(e, StatusCodes.CREATE_ACCOUNT_FAILED,
                     user.toString());
@@ -509,11 +516,11 @@
     }
 
     //todo:
-    private ShibUser createShibbUserAccount(Map<String, String> attributes)
+    private ShibUser createShibbUserAccount(Map<String, Object> attributes)
             throws KustvaktException {
         jlog.debug("creating shibboleth user account for user attr: {}",
                 attributes);
-        Map<String, String> safeMap = crypto.validateMap(attributes);
+        Map<String, Object> safeMap = crypto.validateMap(attributes);
 
         //todo eppn non-unique.join with idp or use persistent_id as username identifier
         ShibUser user = User.UserFactory
@@ -634,9 +641,10 @@
                     username), StatusCodes.PASSWORD_RESET_FAILED, username);
         }
 
-        getUserDetails(ident);
+        Userdata data = this.getUserData(ident, Userdetails2.class);
         KorAPUser user = (KorAPUser) ident;
-        if (!mail.equals(user.getDetails().getEmail()))
+
+        if (!mail.equals(data.get(Attributes.EMAIL)))
             //            throw new NotAuthorizedException(StatusCodes.ILLEGAL_ARGUMENT,
             //                    "invalid parameter: email", "email");
             throw new WrappedException(new KustvaktException(user.getId(),
@@ -657,61 +665,53 @@
                 new DateTime(param.getUriExpiration()) };
     }
 
-    public void updateUserSettings(User user, UserSettings settings)
-            throws KustvaktException {
-        if (user instanceof DemoUser)
-            return;
-        else {
-            Map map = crypto.validateMap(settings.toObjectMap());
-            settings = UserSettings.fromObjectMap(map);
-            try {
-                entHandler.updateSettings(settings);
-            }catch (KustvaktException e) {
-                jlog.error("Error ", e);
-                throw new WrappedException(e,
-                        StatusCodes.UPDATE_ACCOUNT_FAILED);
-            }
-        }
-    }
+    @Override
+    public <T extends Userdata> T getUserData(User user, Class<T> clazz)
+            throws WrappedException {
 
-    public void updateUserDetails(User user, UserDetails details)
-            throws KustvaktException {
-        if (user instanceof DemoUser)
-            return;
-        else {
-            Map map = crypto.validateMap(details.toMap());
-
-            try {
-                entHandler
-                        .updateUserDetails(UserDetails.newDetailsIterator(map));
-            }catch (KustvaktException e) {
-                jlog.error("Error ", e);
-                throw new WrappedException(e,
-                        StatusCodes.UPDATE_ACCOUNT_FAILED);
-            }
-        }
-    }
-
-    public UserDetails getUserDetails(User user) throws KustvaktException {
         try {
-            if (user.getDetails() == null)
-                user.setDetails(entHandler.getUserDetails(user.getId()));
+            UserDataDbIface<T> dao = UserdataFactory.getDaoInstance(clazz);
+            return dao.get(user);
         }catch (KustvaktException e) {
+            jlog.error("Error ", e);
             throw new WrappedException(e, StatusCodes.GET_ACCOUNT_FAILED);
         }
-        return user.getDetails();
     }
 
-    public UserSettings getUserSettings(User user) throws KustvaktException {
+    //todo: cache userdata outside of the user object!
+    @Override
+    public void updateUserData(Userdata data) throws WrappedException {
         try {
-            if (user.getSettings() == null)
-                user.setSettings(entHandler.getUserSettings(user.getId()));
+            data.validate(this.crypto);
+            UserDataDbIface dao = UserdataFactory
+                    .getDaoInstance(data.getClass());
+            dao.update(data);
         }catch (KustvaktException e) {
-            throw new WrappedException(e, StatusCodes.GET_ACCOUNT_FAILED);
+            jlog.error("Error ", e);
+            throw new WrappedException(e, StatusCodes.UPDATE_ACCOUNT_FAILED);
         }
-        return user.getSettings();
     }
 
+    //    public UserDetails getUserDetails(User user) throws KustvaktException {
+    //        try {
+    //            if (user.getDetails() == null)
+    //                user.setDetails(entHandler.getUserDetails(user.getId()));
+    //        }catch (KustvaktException e) {
+    //            throw new WrappedException(e, StatusCodes.GET_ACCOUNT_FAILED);
+    //        }
+    //        return user.getDetails();
+    //    }
+    //
+    //    public UserSettings getUserSettings(User user) throws KustvaktException {
+    //        try {
+    //            if (user.getSettings() == null)
+    //                user.setSettings(entHandler.getUserSettings(user.getId()));
+    //        }catch (KustvaktException e) {
+    //            throw new WrappedException(e, StatusCodes.GET_ACCOUNT_FAILED);
+    //        }
+    //        return user.getSettings();
+    //    }
+
     private String cache_key(String input) throws KustvaktException {
         try {
             return crypto.hash(KEY + "@" + input);
diff --git a/src/main/java/de/ids_mannheim/korap/security/auth/OpenIDconnectAuthentication.java b/src/main/java/de/ids_mannheim/korap/security/auth/OpenIDconnectAuthentication.java
index a1871c9..3f0ebe4 100644
--- a/src/main/java/de/ids_mannheim/korap/security/auth/OpenIDconnectAuthentication.java
+++ b/src/main/java/de/ids_mannheim/korap/security/auth/OpenIDconnectAuthentication.java
@@ -44,9 +44,9 @@
     }
 
     @Override
-    public TokenContext createUserSession(User user, Map<String, String> attr)
+    public TokenContext createUserSession(User user, Map<String, Object> attr)
             throws KustvaktException {
-        String cl_secret = attr.get(Attributes.CLIENT_SECRET);
+        String cl_secret = (String) attr.get(Attributes.CLIENT_SECRET);
         if (cl_secret == null)
             throw new KustvaktException(StatusCodes.REQUEST_INVALID);
         attr.remove(cl_secret);
diff --git a/src/main/java/de/ids_mannheim/korap/security/auth/SessionAuthentication.java b/src/main/java/de/ids_mannheim/korap/security/auth/SessionAuthentication.java
index 3a74954..68b04c8 100644
--- a/src/main/java/de/ids_mannheim/korap/security/auth/SessionAuthentication.java
+++ b/src/main/java/de/ids_mannheim/korap/security/auth/SessionAuthentication.java
@@ -56,7 +56,7 @@
     }
 
     @Override
-    public TokenContext createUserSession(User user, Map attr)
+    public TokenContext createUserSession(User user, Map<String, Object> attr)
             throws KustvaktException {
         DateTime now = TimeUtils.getNow();
         DateTime ex = TimeUtils
diff --git a/src/main/java/de/ids_mannheim/korap/user/DemoUser.java b/src/main/java/de/ids_mannheim/korap/user/DemoUser.java
index c88f5e1..70eb878 100644
--- a/src/main/java/de/ids_mannheim/korap/user/DemoUser.java
+++ b/src/main/java/de/ids_mannheim/korap/user/DemoUser.java
@@ -19,7 +19,7 @@
         this.setDetails(new UserDetails());
         this.setSettings(new UserSettings());
         this.setAccountCreation(ACCOUNT_CREATED);
-        this.setQueries(UserQuery.demoUserQueries());
+//        this.setQueries(UserQuery.demoUserQueries());
     }
 
     protected User clone() {
diff --git a/src/main/java/de/ids_mannheim/korap/user/TokenContext.java b/src/main/java/de/ids_mannheim/korap/user/TokenContext.java
index 9eeff3a..a31beab 100644
--- a/src/main/java/de/ids_mannheim/korap/user/TokenContext.java
+++ b/src/main/java/de/ids_mannheim/korap/user/TokenContext.java
@@ -33,7 +33,7 @@
 
     @Getter(AccessLevel.PRIVATE)
     @Setter(AccessLevel.PRIVATE)
-    private Map<String, String> parameters;
+    private Map<String, Object> parameters;
     private String hostAddress;
     private String userAgent;
 
@@ -54,7 +54,7 @@
         return m;
     }
 
-    public Map<String, String> params() {
+    public Map<String, Object> params() {
         return new HashMap<>(parameters);
     }
 
diff --git a/src/main/java/de/ids_mannheim/korap/user/User.java b/src/main/java/de/ids_mannheim/korap/user/User.java
index 5c4510e..22c8188 100644
--- a/src/main/java/de/ids_mannheim/korap/user/User.java
+++ b/src/main/java/de/ids_mannheim/korap/user/User.java
@@ -5,10 +5,14 @@
 import de.ids_mannheim.korap.utils.JsonUtils;
 import de.ids_mannheim.korap.utils.TimeUtils;
 import de.ids_mannheim.korap.web.utils.KustvaktMap;
+import lombok.AccessLevel;
 import lombok.Data;
+import lombok.Getter;
+import lombok.Setter;
 import org.joda.time.DateTime;
 
 import java.io.Serializable;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -26,16 +30,26 @@
     private boolean isAccountLocked;
     private int type;
     private ParamFields fields;
+    @Getter(AccessLevel.PRIVATE)
+    @Setter(AccessLevel.PRIVATE)
     private UserSettings settings;
+    //todo: remove!
+    @Getter(AccessLevel.PRIVATE)
+    @Setter(AccessLevel.PRIVATE)
     private UserDetails details;
+    @Getter(AccessLevel.PRIVATE)
+    @Setter(AccessLevel.PRIVATE)
     private List<UserQuery> queries;
 
+    private List<Userdata> userdata;
+
     protected User() {
         this.fields = new ParamFields();
         this.accountCreation = TimeUtils.getNow().getMillis();
         this.isAccountLocked = false;
         this.username = "";
         this.id = -1;
+        this.userdata = new ArrayList<>();
     }
 
     protected User(int type) {
@@ -58,35 +72,49 @@
 
     //todo: repair transfer
     public void transfer(User user) {
-        this.setSettings(user.getSettings());
-        this.setDetails(user.getDetails());
+        //        this.setSettings(user.getSettings());
+        //        this.setDetails(user.getDetails());
         //        this.setQueries(user.getQueries());
         if (this instanceof KorAPUser) {
-            this.getSettings().setUserID(this.id);
-            this.getDetails().setUserID(this.id);
+
+            //            this.getSettings().setUserID(this.id);
+            //            this.getDetails().setUserID(this.id);
             //            for (UserQuery q : this.getQueries())
             //                q.setOwner(this.accountID);
         }
     }
 
+    public void addUserData(Userdata data) {
+        if (data != null) {
+            for (Userdata d : this.userdata) {
+                // already has an object of that type!
+                if (d.getClass().equals(data.getClass()))
+                    return;
+            }
+            userdata.add(data);
+        }
+    }
+
+    @Deprecated
     public void setDetails(UserDetails details) {
         if (details != null)
             details.setUserID(this.id);
-        this.details = details;
+        //        this.details = details;
     }
 
+    @Deprecated
     public void setSettings(UserSettings settings) {
         if (settings != null)
             settings.setUserID(this.id);
-        this.settings = settings;
+        //        this.settings = settings;
     }
 
     public void setId(Integer id) {
         this.id = id;
-        if (this.settings != null)
-            this.settings.setUserID(this.id);
-        if (this.details != null)
-            this.details.setUserID(this.id);
+        //        if (this.settings != null)
+        //            this.settings.setUserID(this.id);
+        //        if (this.details != null)
+        //            this.details.setUserID(this.id);
     }
 
     public Map<String, Object> toMap() {
@@ -95,15 +123,11 @@
         //TimeUtils.format(new DateTime(this.accountCreation))
         map.put(Attributes.ACCOUNT_CREATION, this.accountCreation);
 
-        if (this.getDetails() != null)
-            map.putAll(this.getDetails().toMap());
+        //        if (this.getDetails() != null)
+        //            map.putAll(this.getDetails().toMap());
         return map;
     }
 
-    public String toJson() {
-        return JsonUtils.toJSON(this.toMap());
-    }
-
     public Map toCache() {
         Map map = new HashMap();
         map.put(Attributes.ID, this.id);
diff --git a/src/main/java/de/ids_mannheim/korap/user/UserDataDbIface.java b/src/main/java/de/ids_mannheim/korap/user/UserDataDbIface.java
new file mode 100644
index 0000000..7ee663c
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/user/UserDataDbIface.java
@@ -0,0 +1,23 @@
+package de.ids_mannheim.korap.user;
+
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+
+/**
+ * @author hanl
+ * @date 27/01/2016
+ */
+public interface UserDataDbIface<T extends Userdata> {
+
+    public int store(T data) throws KustvaktException;
+
+    public int update(T data) throws KustvaktException;
+
+    public T get(Integer id) throws KustvaktException;
+
+    public T get(User user) throws KustvaktException;
+
+    public int delete(T data) throws KustvaktException;
+
+    public int deleteAll() throws KustvaktException;
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/user/UserDetails.java b/src/main/java/de/ids_mannheim/korap/user/UserDetails.java
index e9d74d0..135fbd2 100644
--- a/src/main/java/de/ids_mannheim/korap/user/UserDetails.java
+++ b/src/main/java/de/ids_mannheim/korap/user/UserDetails.java
@@ -13,6 +13,7 @@
  */
 
 // todo: set certain fields required!
+@Deprecated
 @Data
 public class UserDetails {
 
diff --git a/src/main/java/de/ids_mannheim/korap/user/UserDetailsDao.java b/src/main/java/de/ids_mannheim/korap/user/UserDetailsDao.java
new file mode 100644
index 0000000..4e16bed
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/user/UserDetailsDao.java
@@ -0,0 +1,134 @@
+package de.ids_mannheim.korap.user;
+
+import de.ids_mannheim.korap.interfaces.db.PersistenceClient;
+import org.springframework.dao.DataAccessException;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
+import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
+import org.springframework.jdbc.support.GeneratedKeyHolder;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.HashMap;
+
+/**
+ * @author hanl
+ * @date 27/01/2016
+ */
+public class UserDetailsDao implements UserDataDbIface<Userdetails2> {
+
+    private NamedParameterJdbcTemplate jdbcTemplate;
+
+    public UserDetailsDao(PersistenceClient client) {
+        this.jdbcTemplate = (NamedParameterJdbcTemplate) client.getSource();
+    }
+
+    @Override
+    public int store(Userdetails2 data) {
+        String sql = "INSERT INTO user_details2 (user_id, data) VALUES (:userid, :data);";
+        MapSqlParameterSource source = new MapSqlParameterSource();
+        source.addValue("userid", data.getUserID());
+        source.addValue("data", data.data());
+
+        GeneratedKeyHolder gen = new GeneratedKeyHolder();
+        try {
+            this.jdbcTemplate.update(sql, source, gen);
+            int id = gen.getKey().intValue();
+            data.setId(id);
+            return id;
+        }catch (DataAccessException e) {
+            e.printStackTrace();
+            return -1;
+        }
+    }
+
+    @Override
+    public int update(Userdetails2 data) {
+        String sql = "UPDATE user_details2 SET data = :data WHERE user_id=:userid;";
+        MapSqlParameterSource source = new MapSqlParameterSource();
+        source.addValue("userid", data.getUserID());
+        source.addValue("data", data.data());
+
+        try {
+            return this.jdbcTemplate.update(sql, source);
+        }catch (DataAccessException e) {
+            return -1;
+        }
+    }
+
+    @Override
+    public Userdetails2 get(Integer id) {
+        String sql = "SELECT * FROM user_details2 WHERE id=:id;";
+        MapSqlParameterSource source = new MapSqlParameterSource();
+        source.addValue("id", id);
+
+        try {
+            return this.jdbcTemplate
+                    .queryForObject(sql, source, new RowMapper<Userdetails2>() {
+
+                        @Override
+                        public Userdetails2 mapRow(ResultSet rs, int rowNum)
+                                throws SQLException {
+                            Userdetails2 details = new Userdetails2(
+                                    rs.getInt("user_id"));
+                            details.setId(rs.getInt("id"));
+                            details.setData(rs.getString("data"));
+                            return details;
+                        }
+                    });
+
+        }catch (DataAccessException e) {
+            return null;
+        }
+    }
+
+    @Override
+    public Userdetails2 get(User user) {
+        String sql = "SELECT * FROM user_details2 WHERE user_id=:userid;";
+        MapSqlParameterSource source = new MapSqlParameterSource();
+        source.addValue("userid", user.getId());
+
+        try {
+            return this.jdbcTemplate
+                    .queryForObject(sql, source, new RowMapper<Userdetails2>() {
+
+                        @Override
+                        public Userdetails2 mapRow(ResultSet rs, int rowNum)
+                                throws SQLException {
+                            Userdetails2 details = new Userdetails2(
+                                    rs.getInt("user_id"));
+                            details.setId(rs.getInt("id"));
+                            details.setData(rs.getString("data"));
+                            return details;
+                        }
+                    });
+
+        }catch (DataAccessException e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    @Override
+    public int delete(Userdetails2 data) {
+        String sql = "DELETE FROM user_details2 WHERE id=:id";
+        MapSqlParameterSource source = new MapSqlParameterSource();
+        source.addValue("id", data.getId());
+        try {
+            return this.jdbcTemplate.update(sql, source);
+        }catch (DataAccessException e) {
+            return -1;
+        }
+    }
+
+    @Override
+    public int deleteAll() {
+        String sql = "DELETE FROM user_details2;";
+        try {
+            return this.jdbcTemplate.update(sql, new HashMap<String, Object>());
+        }catch (DataAccessException e) {
+            e.printStackTrace();
+            return -1;
+        }
+    }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/user/UserSettings.java b/src/main/java/de/ids_mannheim/korap/user/UserSettings.java
index 046ef56..77351e9 100644
--- a/src/main/java/de/ids_mannheim/korap/user/UserSettings.java
+++ b/src/main/java/de/ids_mannheim/korap/user/UserSettings.java
@@ -15,6 +15,7 @@
  * Time: 10:26 AM
  */
 
+@Deprecated
 @Getter
 @Setter
 public class UserSettings {
diff --git a/src/main/java/de/ids_mannheim/korap/user/UserSettings2.java b/src/main/java/de/ids_mannheim/korap/user/UserSettings2.java
new file mode 100644
index 0000000..d6b86a9
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/user/UserSettings2.java
@@ -0,0 +1,23 @@
+package de.ids_mannheim.korap.user;
+
+/**
+ * @author hanl
+ * @date 28/01/2016
+ */
+public class UserSettings2 extends Userdata {
+
+
+    public UserSettings2(Integer userid) {
+        super(userid);
+    }
+
+    @Override
+    public String[] requiredFields() {
+        return new String[0];
+    }
+
+    @Override
+    public String[] defaultFields() {
+        return new String[0];
+    }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/user/UserSettingsDao.java b/src/main/java/de/ids_mannheim/korap/user/UserSettingsDao.java
new file mode 100644
index 0000000..c82ac64
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/user/UserSettingsDao.java
@@ -0,0 +1,133 @@
+package de.ids_mannheim.korap.user;
+
+import de.ids_mannheim.korap.interfaces.db.PersistenceClient;
+import org.springframework.dao.DataAccessException;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
+import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
+import org.springframework.jdbc.support.GeneratedKeyHolder;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.HashMap;
+
+/**
+ * @author hanl
+ * @date 28/01/2016
+ */
+public class UserSettingsDao implements UserDataDbIface<UserSettings2> {
+
+    NamedParameterJdbcTemplate jdbcTemplate;
+
+    public UserSettingsDao(PersistenceClient client) {
+        this.jdbcTemplate = (NamedParameterJdbcTemplate) client.getSource();
+    }
+    @Override
+    public int store(UserSettings2 data) {
+        String sql = "INSERT INTO user_settings2 (user_id, data) VALUES (:userid, :data);";
+        MapSqlParameterSource source = new MapSqlParameterSource();
+        source.addValue("userid", data.getUserID());
+        source.addValue("data", data.data());
+
+        GeneratedKeyHolder gen = new GeneratedKeyHolder();
+        try {
+            this.jdbcTemplate.update(sql, source, gen);
+            int id = gen.getKey().intValue();
+            data.setId(id);
+            return id;
+        }catch (DataAccessException e) {
+            e.printStackTrace();
+            return -1;
+        }
+    }
+
+    @Override
+    public int update(UserSettings2 data) {
+        String sql = "UPDATE user_settings2 SET data = :data WHERE user_id=:userid;";
+        MapSqlParameterSource source = new MapSqlParameterSource();
+        source.addValue("userid", data.getUserID());
+        source.addValue("data", data.data());
+
+        try {
+            return this.jdbcTemplate.update(sql, source);
+        }catch (DataAccessException e) {
+            return -1;
+        }
+    }
+
+    @Override
+    public UserSettings2 get(Integer id) {
+        String sql = "SELECT * FROM user_settings2 WHERE id=:id;";
+        MapSqlParameterSource source = new MapSqlParameterSource();
+        source.addValue("id", id);
+
+        try {
+            return this.jdbcTemplate
+                    .queryForObject(sql, source, new RowMapper<UserSettings2>() {
+
+                        @Override
+                        public UserSettings2 mapRow(ResultSet rs, int rowNum)
+                                throws SQLException {
+                            UserSettings2 details = new UserSettings2(
+                                    rs.getInt("user_id"));
+                            details.setId(rs.getInt("id"));
+                            details.setData(rs.getString("data"));
+                            return details;
+                        }
+                    });
+
+        }catch (DataAccessException e) {
+            return null;
+        }
+    }
+
+    @Override
+    public UserSettings2 get(User user) {
+        String sql = "SELECT * FROM user_settings2 WHERE user_id=:userid;";
+        MapSqlParameterSource source = new MapSqlParameterSource();
+        source.addValue("userid", user.getId());
+
+        try {
+            return this.jdbcTemplate
+                    .queryForObject(sql, source, new RowMapper<UserSettings2>() {
+
+                        @Override
+                        public UserSettings2 mapRow(ResultSet rs, int rowNum)
+                                throws SQLException {
+                            UserSettings2 details = new UserSettings2(
+                                    rs.getInt("user_id"));
+                            details.setId(rs.getInt("id"));
+                            details.setData(rs.getString("data"));
+                            return details;
+                        }
+                    });
+
+        }catch (DataAccessException e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    @Override
+    public int delete(UserSettings2 data) {
+        String sql = "DELETE FROM user_settings2 WHERE id=:id";
+        MapSqlParameterSource source = new MapSqlParameterSource();
+        source.addValue("id", data.getId());
+        try {
+            return this.jdbcTemplate.update(sql, source);
+        }catch (DataAccessException e) {
+            return -1;
+        }
+    }
+
+    @Override
+    public int deleteAll() {
+        String sql = "DELETE FROM user_settings2;";
+        try {
+            return this.jdbcTemplate.update(sql, new HashMap<String, Object>());
+        }catch (DataAccessException e) {
+            e.printStackTrace();
+            return -1;
+        }
+    }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/user/Userdata.java b/src/main/java/de/ids_mannheim/korap/user/Userdata.java
new file mode 100644
index 0000000..bf53486
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/user/Userdata.java
@@ -0,0 +1,134 @@
+package de.ids_mannheim.korap.user;
+
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.exceptions.StatusCodes;
+import de.ids_mannheim.korap.interfaces.EncryptionIface;
+import de.ids_mannheim.korap.utils.JsonUtils;
+import lombok.AccessLevel;
+import lombok.Data;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.*;
+
+/**
+ * @author hanl
+ * @date 22/01/2016
+ */
+@Data
+public abstract class Userdata {
+
+    private Integer id;
+    @Getter(AccessLevel.PRIVATE)
+    @Setter(AccessLevel.PRIVATE)
+    private Map<String, Object> fields;
+    @Setter(AccessLevel.PRIVATE)
+    private Integer userID;
+
+    public Userdata(Integer userid) {
+        this.fields = new HashMap<>();
+        this.userID = userid;
+        this.id = -1;
+    }
+
+    public void setData(Map<String, Object> map) throws KustvaktException {
+        Set missing = missing(map);
+        if (!missing.isEmpty())
+            throw new KustvaktException(StatusCodes.MISSING_ARGUMENTS,
+                    missing.toString());
+        this.fields.clear();
+        this.fields.putAll(map);
+    }
+
+    private Set<String> missing(Map<String, Object> map) {
+        Set<String> missing = new HashSet<>();
+        for (String key : requiredFields()) {
+            if (!map.containsKey(key))
+                missing.add(key);
+        }
+        return missing;
+    }
+
+    public int size() {
+        return this.fields.size();
+    }
+
+    public Object get(String key) {
+        return this.fields.get(key);
+    }
+
+    public boolean isValid() {
+        //        return this.missing(this.fields).isEmpty() && this.userID != -1;
+        return missing().length == 0;
+    }
+
+    public String[] missing() {
+        StringBuilder b = new StringBuilder();
+        Set<String> m = missing(this.fields);
+
+        if (m.isEmpty())
+            return new String[0];
+
+        for (String k : m) {
+            b.append(k).append(";");
+        }
+        return b.toString().split(";");
+    }
+
+    public void checkRequired() throws KustvaktException {
+        if (!isValid()) {
+            String[] fields = missing();
+            throw new KustvaktException(StatusCodes.MISSING_ARGUMENTS,
+                    "User data object not valid. Missing fields: " + Arrays
+                            .asList(fields));
+        }
+    }
+
+    public Set<String> keys() {
+        return this.fields.keySet();
+    }
+
+    public Collection<Object> values() {
+        return this.fields.values();
+    }
+
+    public Map<String, Object> fields() {
+        return new HashMap<>(this.fields);
+    }
+
+    public void setData(String data) {
+        Map m = JsonUtils.readSimple(data, Map.class);
+        if (m != null)
+            this.fields.putAll(m);
+    }
+
+    public void update(Userdata other) {
+        if (other != null && this.getClass().equals(other.getClass()))
+            this.fields.putAll(other.fields);
+    }
+
+    public String data() {
+        return JsonUtils.toJSON(this.fields);
+    }
+
+    public void addField(String key, Object value) {
+        this.fields.put(key, value);
+    }
+
+    public void validate(EncryptionIface crypto) throws KustvaktException {
+        this.fields = crypto.validateMap(this.fields);
+    }
+
+    public void readDefaults(Map<String, Object> map) {
+        for (String k : defaultFields()) {
+            Object o = map.get(k);
+            if (o != null)
+                this.fields.put(k, o);
+        }
+    }
+
+    public abstract String[] requiredFields();
+
+    public abstract String[] defaultFields();
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/user/UserdataFactory.java b/src/main/java/de/ids_mannheim/korap/user/UserdataFactory.java
new file mode 100644
index 0000000..35cc02b
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/user/UserdataFactory.java
@@ -0,0 +1,65 @@
+package de.ids_mannheim.korap.user;
+
+import de.ids_mannheim.korap.config.BeanConfiguration;
+import de.ids_mannheim.korap.config.KustvaktClassLoader;
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.exceptions.StatusCodes;
+import de.ids_mannheim.korap.interfaces.db.PersistenceClient;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author hanl
+ * @date 27/01/2016
+ */
+public class UserdataFactory {
+
+    private static final Map<Class<? extends Userdata>, UserDataDbIface> instances = new HashMap<>();
+
+    private UserdataFactory() {
+    }
+
+    public static Class<? extends UserDataDbIface> getClass(
+            Class<? extends Userdata> data) {
+        Set<Class<? extends UserDataDbIface>> c = KustvaktClassLoader
+                .loadSubTypes(UserDataDbIface.class);
+        for (Class<? extends UserDataDbIface> o : c) {
+            Type type = o.getGenericInterfaces()[0];
+            if (type instanceof ParameterizedType) {
+                ParameterizedType ptype = (ParameterizedType) type;
+                Class ctype = (Class) ptype.getActualTypeArguments()[0];
+                if (ctype.equals(data))
+                    return o;
+            }
+        }
+        return null;
+    }
+
+    public static UserDataDbIface getDaoInstance(
+            Class<? extends Userdata> data) throws KustvaktException {
+        if (instances.get(data) == null) {
+            Class<? extends UserDataDbIface> cl = getClass(data);
+            if (BeanConfiguration.hasContext() && cl != null) {
+                try {
+                    Constructor c = cl.getConstructor(PersistenceClient.class);
+                    UserDataDbIface iface = (UserDataDbIface) c.newInstance(
+                            BeanConfiguration.getBeans()
+                                    .getPersistenceClient());
+                    instances.put(data, iface);
+                    return iface;
+                }catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException e) {
+                    return null;
+                }
+            }
+            throw new KustvaktException(StatusCodes.NOT_SUPPORTED,
+                    "No database class found for type " + data.getSimpleName());
+        }else
+            return instances.get(data);
+    }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/user/Userdetails2.java b/src/main/java/de/ids_mannheim/korap/user/Userdetails2.java
new file mode 100644
index 0000000..0f40f57
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/user/Userdetails2.java
@@ -0,0 +1,27 @@
+package de.ids_mannheim.korap.user;
+
+/**
+ * @author hanl
+ * @date 22/01/2016
+ * persistence issue with query request
+ */
+public class Userdetails2 extends Userdata {
+
+    public Userdetails2(Integer userid) {
+        super(userid);
+    }
+
+    @Override
+    public String[] requiredFields() {
+        return new String[] { Attributes.EMAIL, Attributes.ADDRESS,
+                Attributes.LASTNAME, Attributes.FIRSTNAME };
+    }
+
+    @Override
+    public String[] defaultFields() {
+        return new String[] { Attributes.EMAIL, Attributes.ADDRESS,
+                Attributes.LASTNAME, Attributes.FIRSTNAME, Attributes.PHONE,
+                Attributes.COUNTRY, Attributes.INSTITUTION, Attributes.GENDER };
+    }
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/web/filter/PiwikFilter.java b/src/main/java/de/ids_mannheim/korap/web/filter/PiwikFilter.java
index 293da84..1d886ed 100644
--- a/src/main/java/de/ids_mannheim/korap/web/filter/PiwikFilter.java
+++ b/src/main/java/de/ids_mannheim/korap/web/filter/PiwikFilter.java
@@ -13,9 +13,7 @@
 import de.ids_mannheim.korap.config.BeanConfiguration;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.interfaces.AuthenticationManagerIface;
-import de.ids_mannheim.korap.user.TokenContext;
-import de.ids_mannheim.korap.user.User;
-import de.ids_mannheim.korap.user.UserSettings;
+import de.ids_mannheim.korap.user.*;
 import net.minidev.json.JSONArray;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -39,11 +37,10 @@
     private static Logger jlog = LoggerFactory.getLogger(PiwikFilter.class);
     public static boolean ENABLED = false;
     private Map<String, String> customVars;
-    private AuthenticationManagerIface securityController;
+    private AuthenticationManagerIface controller;
 
     public PiwikFilter() {
-        securityController = BeanConfiguration.getBeans()
-                .getAuthenticationManager();
+        controller = BeanConfiguration.getBeans().getAuthenticationManager();
         ClientConfig config = new DefaultClientConfig();
         Client client = Client.create(config);
         if (jlog.isDebugEnabled())
@@ -69,8 +66,8 @@
         if (request.getAcceptableLanguages() != null)
             l = request.getAcceptableLanguages().get(0);
         try {
-            service.path("piwik/piwik.php")
-                    .queryParam("idsite", "2").queryParam("rec", "1")
+            service.path("piwik/piwik.php").queryParam("idsite", "2")
+                    .queryParam("rec", "1")
                     //todo check for empty container
                     .queryParam("_cvar", translateCustomData())
                     .queryParam("cip", request.getHeaderValue("Host"))
@@ -116,10 +113,10 @@
                 TokenContext context = (TokenContext) request
                         .getUserPrincipal();
                 // since this is cached, not very expensive!
-                User user = securityController.getUser(context.getUsername());
-                UserSettings settiings = securityController
-                        .getUserSettings(user);
-                if (settiings.isCollectData())
+                User user = controller.getUser(context.getUsername());
+                Userdata data = controller
+                        .getUserData(user, UserSettings2.class);
+                if ((Boolean) data.get(Attributes.COLLECT_AUDITING_DATA))
                     customVars.put("username", context.getUsername());
             }catch (KustvaktException | UnsupportedOperationException e) {
                 //do nothing
diff --git a/src/main/java/de/ids_mannheim/korap/web/service/full/AuthService.java b/src/main/java/de/ids_mannheim/korap/web/service/full/AuthService.java
index f53c816..86424c5 100644
--- a/src/main/java/de/ids_mannheim/korap/web/service/full/AuthService.java
+++ b/src/main/java/de/ids_mannheim/korap/web/service/full/AuthService.java
@@ -7,10 +7,7 @@
 import de.ids_mannheim.korap.exceptions.StatusCodes;
 import de.ids_mannheim.korap.interfaces.AuthenticationManagerIface;
 import de.ids_mannheim.korap.security.auth.BasicHttpAuth;
-import de.ids_mannheim.korap.user.Attributes;
-import de.ids_mannheim.korap.user.TokenContext;
-import de.ids_mannheim.korap.user.User;
-import de.ids_mannheim.korap.user.UserSettings;
+import de.ids_mannheim.korap.user.*;
 import de.ids_mannheim.korap.utils.JsonUtils;
 import de.ids_mannheim.korap.utils.KustvaktLogger;
 import de.ids_mannheim.korap.utils.ServiceVersion;
@@ -110,7 +107,7 @@
             // is actual an invalid request
             throw KustvaktResponseHandler.throwit(StatusCodes.REQUEST_INVALID);
 
-        Map<String, String> attr = new HashMap<>();
+        Map<String, Object> attr = new HashMap<>();
         if (scopes != null && !scopes.isEmpty())
             attr.put(Attributes.SCOPES, scopes);
         attr.put(Attributes.HOST, host);
@@ -118,7 +115,10 @@
         TokenContext context;
         try {
             User user = controller.authenticate(0, values[0], values[1], attr);
-            this.controller.getUserDetails(user);
+            Userdata data = this.controller
+                    .getUserData(user, Userdetails2.class);
+            // todo: is this necessary?
+//            attr.putAll(data.fields());
             context = controller.createTokenContext(user, attr,
                     Attributes.API_AUTHENTICATION);
         }catch (KustvaktException e) {
@@ -175,7 +175,7 @@
                 .equalsIgnoreCase("null"))
             throw KustvaktResponseHandler.throwit(StatusCodes.REQUEST_INVALID);
 
-        Map<String, String> attr = new HashMap<>();
+        Map<String, Object> attr = new HashMap<>();
         attr.put(Attributes.HOST, host);
         attr.put(Attributes.USER_AGENT, agent);
         TokenContext context;
@@ -204,7 +204,7 @@
         // the shibfilter decrypted the values
         // define default provider for returned access token strategy?!
 
-        Map<String, String> attr = new HashMap<>();
+        Map<String, Object> attr = new HashMap<>();
         attr.put(Attributes.HOST, host);
         attr.put(Attributes.USER_AGENT, agent);
 
diff --git a/src/main/java/de/ids_mannheim/korap/web/service/full/OAuthService.java b/src/main/java/de/ids_mannheim/korap/web/service/full/OAuthService.java
index 11fc0b3..c516364 100644
--- a/src/main/java/de/ids_mannheim/korap/web/service/full/OAuthService.java
+++ b/src/main/java/de/ids_mannheim/korap/web/service/full/OAuthService.java
@@ -8,9 +8,7 @@
 import de.ids_mannheim.korap.handlers.OAuth2Handler;
 import de.ids_mannheim.korap.interfaces.AuthenticationManagerIface;
 import de.ids_mannheim.korap.interfaces.EncryptionIface;
-import de.ids_mannheim.korap.user.Attributes;
-import de.ids_mannheim.korap.user.TokenContext;
-import de.ids_mannheim.korap.user.User;
+import de.ids_mannheim.korap.user.*;
 import de.ids_mannheim.korap.utils.JsonUtils;
 import de.ids_mannheim.korap.utils.StringUtils;
 import de.ids_mannheim.korap.web.KustvaktServer;
@@ -124,10 +122,12 @@
     public Response getStatus(@Context SecurityContext context,
             @QueryParam("scope") String scopes) {
         TokenContext ctx = (TokenContext) context.getUserPrincipal();
-        User user;
+        Map<String, Object> details;
         try {
-            user = this.controller.getUser(ctx.getUsername());
-            this.controller.getUserDetails(user);
+            User user = this.controller.getUser(ctx.getUsername());
+            Userdata data = this.controller
+                    .getUserData(user, Userdetails2.class);
+            details = data.fields();
             Set<String> base_scope = StringUtils.toSet(scopes, " ");
             base_scope.retainAll(StringUtils.toSet(scopes));
             scopes = StringUtils.toString(base_scope);
@@ -136,8 +136,8 @@
         }
         // json format with scope callback parameter
         // todo: add other scopes as well!
-        return Response.ok(JsonUtils.toJSON(Scopes
-                .mapScopes(scopes, user.getDetails()))).build();
+        return Response.ok(JsonUtils
+                .toJSON(Scopes.mapScopes(scopes, details))).build();
     }
 
     @GET
@@ -172,7 +172,7 @@
             @Context SecurityContext context,
             @HeaderParam(ContainerRequest.USER_AGENT) String agent,
             @HeaderParam(ContainerRequest.HOST) String host,
-            MultivaluedMap<String, String> form)
+            MultivaluedMap<String, Object> form)
             throws OAuthSystemException, URISyntaxException {
         // user needs to be authenticated to this service!
         TokenContext c = (TokenContext) context.getUserPrincipal();
@@ -184,7 +184,7 @@
                     new MD5Generator());
             User user;
 
-            Map<String, String> attr = new HashMap<>();
+            Map<String, Object> attr = new HashMap<>();
             attr.put(Attributes.HOST, host);
             attr.put(Attributes.USER_AGENT, agent);
             attr.put(Attributes.USERNAME, c.getUsername());
@@ -198,7 +198,9 @@
 
             try {
                 user = controller.getUser(c.getUsername());
-                controller.getUserDetails(user);
+                Userdata data = controller
+                        .getUserData(user, Userdetails2.class);
+                user.addUserData(data);
             }catch (KustvaktException e) {
                 throw KustvaktResponseHandler.throwit(e);
             }
@@ -436,7 +438,7 @@
                         .entity(res.getBody()).build();
             }
 
-            Map<String, String> attr = new HashMap<>();
+            Map<String, Object> attr = new HashMap<>();
             attr.put(Attributes.HOST, host);
             attr.put(Attributes.USER_AGENT, agent);
             attr.put(Attributes.SCOPES,
@@ -540,7 +542,10 @@
                         user = controller
                                 .authenticate(0, oauthRequest.getUsername(),
                                         oauthRequest.getPassword(), attr);
-                    controller.getUserDetails(user);
+                    Userdata data = controller
+                            .getUserData(user, Userdetails2.class);
+                    user.addUserData(data);
+
                     attr.put(Attributes.CLIENT_SECRET,
                             oauthRequest.getClientSecret());
                     TokenContext c = controller.createTokenContext(user, attr,
diff --git a/src/main/java/de/ids_mannheim/korap/web/service/full/ResourceService.java b/src/main/java/de/ids_mannheim/korap/web/service/full/ResourceService.java
index 7bb87e7..7a6b249 100644
--- a/src/main/java/de/ids_mannheim/korap/web/service/full/ResourceService.java
+++ b/src/main/java/de/ids_mannheim/korap/web/service/full/ResourceService.java
@@ -669,7 +669,7 @@
             //todo ?!
             CollectionQueryBuilder3 query = new CollectionQueryBuilder3();
             if (resource instanceof VirtualCollection) {
-                query.setBaseQuery((String) resource.getData());
+                query.setBaseQuery(resource.getData());
             }else if (resource instanceof Corpus) {
                 query.addQuery("corpusID=" + resource.getName());
             }
diff --git a/src/main/java/de/ids_mannheim/korap/web/service/full/UserService.java b/src/main/java/de/ids_mannheim/korap/web/service/full/UserService.java
index d76d02f..03b19bc 100644
--- a/src/main/java/de/ids_mannheim/korap/web/service/full/UserService.java
+++ b/src/main/java/de/ids_mannheim/korap/web/service/full/UserService.java
@@ -59,27 +59,20 @@
     public Response signUp(
             @HeaderParam(ContainerRequest.USER_AGENT) String agent,
             @HeaderParam(ContainerRequest.HOST) String host,
-            @Context Locale locale,
-            MultivaluedMap<String, String> form_values) {
-        Map<String, String> wrapper = FormRequestWrapper
+            @Context Locale locale, MultivaluedMap form_values) {
+        Map<String, Object> wrapper = FormRequestWrapper
                 .toMap(form_values, true);
 
         wrapper.put(Attributes.HOST, host);
         wrapper.put(Attributes.USER_AGENT, agent);
         UriBuilder uriBuilder;
         User user;
-        if (wrapper.get(Attributes.EMAIL) == null)
-            throw KustvaktResponseHandler
-                    .throwit(StatusCodes.ILLEGAL_ARGUMENT, "parameter missing",
-                            "email");
-
         try {
             uriBuilder = info.getBaseUriBuilder();
             uriBuilder.path(KustvaktServer.API_VERSION).path("user")
                     .path("confirm");
 
             user = controller.createUserAccount(wrapper, true);
-
         }catch (KustvaktException e) {
             throw KustvaktResponseHandler.throwit(e);
         }
@@ -217,18 +210,19 @@
     public Response getStatus(@Context SecurityContext context,
             @QueryParam("scopes") String scopes) {
         TokenContext ctx = (TokenContext) context.getUserPrincipal();
-        User user;
+        Scopes m;
         try {
-            user = controller.getUser(ctx.getUsername());
-            controller.getUserDetails(user);
+            User user = controller.getUser(ctx.getUsername());
+            Userdata data = controller.getUserData(user, Userdetails2.class);
+
             Set<String> base_scope = StringUtils.toSet(scopes, " ");
             if (scopes != null)
                 base_scope.retainAll(StringUtils.toSet(scopes));
             scopes = StringUtils.toString(base_scope);
+            m = Scopes.mapScopes(scopes, data.fields());
         }catch (KustvaktException e) {
             throw KustvaktResponseHandler.throwit(e);
         }
-        Scopes m = Scopes.mapScopes(scopes, user.getDetails());
         return Response.ok(m.toEntity()).build();
     }
 
@@ -239,19 +233,17 @@
     public Response getUserSettings(@Context SecurityContext context,
             @Context Locale locale) {
         TokenContext ctx = (TokenContext) context.getUserPrincipal();
-        User user;
+        String result;
         try {
-            user = controller.getUser(ctx.getUsername());
-            controller.getUserSettings(user);
-
+            User user = controller.getUser(ctx.getUsername());
+            Userdata data = controller.getUserData(user, UserSettings2.class);
+            data.addField(Attributes.USERNAME, ctx.getUsername());
+            result = data.data();
         }catch (KustvaktException e) {
             jlog.error("Exception encountered!", e);
             throw KustvaktResponseHandler.throwit(e);
         }
-
-        Map m = user.getSettings().toObjectMap();
-        m.put(Attributes.USERNAME, ctx.getUsername());
-        return Response.ok(JsonUtils.toJSON(m)).build();
+        return Response.ok(result).build();
     }
 
     // todo: test
@@ -261,24 +253,27 @@
     @ResourceFilters({ AuthFilter.class, DefaultFilter.class,
             PiwikFilter.class })
     public Response updateSettings(@Context SecurityContext context,
-            @Context Locale locale, MultivaluedMap<String, String> form) {
+            @Context Locale locale, MultivaluedMap form) {
         TokenContext ctx = (TokenContext) context.getUserPrincipal();
-        Map<String, String> settings = FormRequestWrapper.toMap(form, false);
+        Map<String, Object> settings = FormRequestWrapper.toMap(form, false);
 
         try {
             User user = controller.getUser(ctx.getUsername());
-            UserSettings us = controller.getUserSettings(user);
+            if (user.isDemo())
+                return Response.notModified().build();
+
+            Userdata data = controller.getUserData(user, UserSettings2.class);
             // todo: check setting only within the scope of user settings permissions; not foundry range. Latter is part of
             // frontend which only displays available foundries and
             //            SecurityManager.findbyId(us.getDefaultConstfoundry(), user, Foundry.class);
             //            SecurityManager.findbyId(us.getDefaultLemmafoundry(), user, Foundry.class);
             //            SecurityManager.findbyId(us.getDefaultPOSfoundry(), user, Foundry.class);
             //            SecurityManager.findbyId(us.getDefaultRelfoundry(), user, Foundry.class);
-            us.updateStringSettings(settings);
+            Userdata new_data = new UserSettings2(user.getId());
+            new_data.setData(JsonUtils.toJSON(settings));
+            data.update(new_data);
 
-            controller.updateUserSettings(user, us);
-            if (user.isDemo())
-                return Response.notModified().build();
+            controller.updateUserData(data);
         }catch (KustvaktException e) {
             jlog.error("Exception encountered!", e);
             throw KustvaktResponseHandler.throwit(e);
@@ -294,18 +289,17 @@
     public Response getDetails(@Context SecurityContext context,
             @Context Locale locale) {
         TokenContext ctx = (TokenContext) context.getUserPrincipal();
-        User user;
+        String result;
         try {
-            user = controller.getUser(ctx.getUsername());
-            controller.getUserDetails(user);
+            User user = controller.getUser(ctx.getUsername());
+            Userdata data = controller.getUserData(user, Userdetails2.class);
+            data.addField(Attributes.USERNAME, ctx.getUsername());
+            result = data.data();
         }catch (KustvaktException e) {
             jlog.error("Exception encountered!", e);
             throw KustvaktResponseHandler.throwit(e);
         }
-
-        Map m = user.getDetails().toMap();
-        m.put(Attributes.USERNAME, ctx.getUsername());
-        return Response.ok(JsonUtils.toJSON(m)).build();
+        return Response.ok(result).build();
     }
 
     @POST
@@ -317,15 +311,19 @@
             @Context Locale locale, MultivaluedMap form) {
         TokenContext ctx = (TokenContext) context.getUserPrincipal();
 
-        Map<String, String> wrapper = FormRequestWrapper.toMap(form, true);
+        Map<String, Object> wrapper = FormRequestWrapper.toMap(form, true);
 
         try {
             User user = controller.getUser(ctx.getUsername());
-            UserDetails det = controller.getUserDetails(user);
-            det.updateDetails(wrapper);
-            controller.updateUserDetails(user, det);
             if (user.isDemo())
                 return Response.notModified().build();
+
+            Userdetails2 new_data = new Userdetails2(user.getId());
+            new_data.setData(JsonUtils.toJSON(wrapper));
+
+            Userdetails2 det = controller.getUserData(user, Userdetails2.class);
+            det.update(new_data);
+            controller.updateUserData(det);
         }catch (KustvaktException e) {
             jlog.error("Exception encountered!", e);
             throw KustvaktResponseHandler.throwit(e);
diff --git a/src/main/java/de/ids_mannheim/korap/web/utils/FormRequestWrapper.java b/src/main/java/de/ids_mannheim/korap/web/utils/FormRequestWrapper.java
index b688ab0..f486b1b 100644
--- a/src/main/java/de/ids_mannheim/korap/web/utils/FormRequestWrapper.java
+++ b/src/main/java/de/ids_mannheim/korap/web/utils/FormRequestWrapper.java
@@ -16,7 +16,7 @@
  */
 public class FormRequestWrapper extends HttpServletRequestWrapper {
 
-    private MultivaluedMap<String, String> form;
+    private MultivaluedMap<String, Object> form;
 
     /**
      * Constructs a request object wrapping the given request.
@@ -25,7 +25,7 @@
      * @throws IllegalArgumentException if the request is null
      */
     public FormRequestWrapper(HttpServletRequest request,
-            MultivaluedMap<String, String> form) {
+            MultivaluedMap<String, Object> form) {
         super(request);
         this.form = form;
     }
@@ -48,7 +48,7 @@
         return values;
     }
 
-    public Map<String, String> singleValueMap() {
+    public Map<String, Object> singleValueMap() {
         return toMap(this.form, false);
     }
 
@@ -57,9 +57,9 @@
      *               in value list and returns the result
      * @return key/value map
      */
-    public static Map<String, String> toMap(MultivaluedMap<String, String> form,
+    public static Map<String, Object> toMap(MultivaluedMap<String, Object> form,
             boolean strict) {
-        HashMap<String, String> map = new HashMap<>();
+        HashMap<String, Object> map = new HashMap<>();
         for (String key : form.keySet()) {
             if (strict && form.get(key).size() > 1)
                 continue;
@@ -74,7 +74,7 @@
     }
 
     public void put(String key, String... values) {
-        this.form.put(key, Arrays.<String>asList(values));
+        this.form.put(key, Arrays.<Object>asList(values));
     }
 
 }
diff --git a/src/main/resources/db/sqlite/V1__Initial_version.sql b/src/main/resources/db/sqlite/V1__Initial_version.sql
index edbf4ee..c26fce3 100644
--- a/src/main/resources/db/sqlite/V1__Initial_version.sql
+++ b/src/main/resources/db/sqlite/V1__Initial_version.sql
@@ -65,6 +65,18 @@
 on delete cascade
 );
 
+CREATE TABLE IF NOT EXISTS user_details2 (
+id INTEGER PRIMARY KEY AUTOINCREMENT,
+user_id INTEGER UNIQUE NOT NULL,
+data BLOB NOT NULL
+);
+
+CREATE TABLE IF NOT EXISTS user_settings2 (
+id INTEGER PRIMARY KEY AUTOINCREMENT,
+user_id INTEGER UNIQUE NOT NULL,
+data BLOB NOT NULL
+);
+
 
 CREATE TABLE IF NOT EXISTS user_queries (
 id INTEGER PRIMARY KEY,
diff --git a/src/test/java/UserdataTest.java b/src/test/java/UserdataTest.java
new file mode 100644
index 0000000..b635ddc
--- /dev/null
+++ b/src/test/java/UserdataTest.java
@@ -0,0 +1,108 @@
+import de.ids_mannheim.korap.config.BeanConfiguration;
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.user.*;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * @author hanl
+ * @date 27/01/2016
+ */
+public class UserdataTest {
+
+    @BeforeClass
+    public static void init() {
+        BeanConfiguration.loadClasspathContext("default-config.xml");
+    }
+
+    @AfterClass
+    public static void drop() {
+        BeanConfiguration.closeApplication();
+    }
+
+    @Before
+    public void clear() {
+        UserDetailsDao dao = new UserDetailsDao(
+                BeanConfiguration.getBeans().getPersistenceClient());
+        assert dao.deleteAll() != -1;
+    }
+
+    @Test
+    public void testDataStore() {
+        User user = new KorAPUser();
+        user.setId(1);
+        UserDetailsDao dao = new UserDetailsDao(
+                BeanConfiguration.getBeans().getPersistenceClient());
+        Userdetails2 d = new Userdetails2(1);
+        d.addField("key_1", "value is a value");
+        assert dao.store(d) != -1;
+    }
+
+    @Test
+    public void testDataGet() {
+        User user = new KorAPUser();
+        user.setId(1);
+        UserDetailsDao dao = new UserDetailsDao(
+                BeanConfiguration.getBeans().getPersistenceClient());
+        Userdetails2 d = new Userdetails2(1);
+        d.addField("key_1", "value is a value");
+        assert dao.store(d) != -1;
+
+        d = dao.get(d.getId());
+        assert d != null;
+        assert "value is a value".equals(d.get("key_1"));
+
+        d = dao.get(user);
+        assert d != null;
+        assert "value is a value".equals(d.get("key_1"));
+    }
+
+    @Test
+    public void testDataValidation() {
+        Userdata data = new Userdetails2(1);
+        data.addField(Attributes.COUNTRY, "Germany");
+
+        String[] req = data.requiredFields();
+        String[] r = data.missing();
+        assert r.length > 0;
+        assert r.length == req.length;
+        assert !data.isValid();
+    }
+
+    @Test
+    public void testSettingsValidation() {
+        Userdata data = new UserSettings2(1);
+        data.addField(Attributes.FILE_FORMAT_FOR_EXPORT, "export");
+
+        String[] req = data.requiredFields();
+        String[] r = data.missing();
+        assert r.length == 0;
+        assert r.length == req.length;
+        assert data.isValid();
+    }
+
+    @Test
+    public void testUserdatafactory() throws KustvaktException {
+        UserDataDbIface dao = UserdataFactory
+                .getDaoInstance(Userdetails2.class);
+        assert UserDetailsDao.class.equals(dao.getClass());
+    }
+
+    @Test(expected = KustvaktException.class)
+    public void testUserdatafactoryError() throws KustvaktException {
+        UserdataFactory.getDaoInstance(new Userdata(1) {
+            @Override
+            public String[] requiredFields() {
+                return new String[0];
+            }
+
+            @Override
+            public String[] defaultFields() {
+                return new String[0];
+            }
+        }.getClass());
+    }
+
+}
diff --git a/src/test/java/de/ids_mannheim/korap/config/TestHelper.java b/src/test/java/de/ids_mannheim/korap/config/TestHelper.java
index 739b16d..c96906d 100644
--- a/src/test/java/de/ids_mannheim/korap/config/TestHelper.java
+++ b/src/test/java/de/ids_mannheim/korap/config/TestHelper.java
@@ -33,6 +33,10 @@
             Map m = new HashMap<>();
             m.put(Attributes.USERNAME, credentials[0]);
             m.put(Attributes.PASSWORD, credentials[1]);
+            m.put(Attributes.FIRSTNAME, "test");
+            m.put(Attributes.LASTNAME, "user");
+            m.put(Attributes.EMAIL, "test@ids-mannheim.de");
+            m.put(Attributes.ADDRESS, "Mannheim");
 
             Assert.assertNotNull("userdatabase handler must not be null", dao);
 
diff --git a/src/test/java/de/ids_mannheim/korap/web/service/KustvaktResourceServiceTest.java b/src/test/java/de/ids_mannheim/korap/web/service/KustvaktResourceServiceTest.java
index 9673bd5..62beae8 100644
--- a/src/test/java/de/ids_mannheim/korap/web/service/KustvaktResourceServiceTest.java
+++ b/src/test/java/de/ids_mannheim/korap/web/service/KustvaktResourceServiceTest.java
@@ -55,7 +55,7 @@
         assert ClientResponse.Status.OK.getStatusCode() == response.getStatus();
 
         JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
-        System.out.println("COLLECTIONS " + node);
+
         assert node.size() > 0;
     }
 
@@ -69,20 +69,22 @@
 
         JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
         assert node != null;
-        System.out.println("JSON NODE RESULT " + node);
+
+        System.out.println("-------------------------------");
+        System.out.println("NODE COLLECTIONS" + node);
         String id = node.path(0).path("id").asText();
 
         response = resource().path(getAPIVersion()).path("collection").path(id)
                 .path("stats").header(Attributes.AUTHORIZATION,
                         BasicHttpAuth.encode("kustvakt", "kustvakt2015"))
                 .get(ClientResponse.class);
-        System.out.println("----------------------------- testStats 2");
-        System.out.println(response.getEntity(String.class));
+
         assert ClientResponse.Status.OK.getStatusCode() == response.getStatus();
         node = JsonUtils.readTree(response.getEntity(String.class));
         assert node != null;
         int docs = node.path("documents").asInt();
-        System.out.println("THE FINAL NODE : " + node);
+        System.out.println("-------------------------------");
+        System.out.println("NODE " + node);
         assert docs > 0 && docs < 15;
     }