diff --git a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/generators/AbstractGenerator.java b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/generators/AbstractGenerator.java
index 790fc4715b045e5008a390b3d00892290b984728..b57ffe55b400a80f052859cb39f177a221f54f79 100644
--- a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/generators/AbstractGenerator.java
+++ b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/generators/AbstractGenerator.java
@@ -128,14 +128,11 @@ public class AbstractGenerator
 
     public static void addProperties(DtoGenerator gen)
     {
-        gen.addPluralFetchedField("Map<String, String>", Map.class.getName(), "properties",
-                        "Properties", PropertyFetchOptions.class)
-                .withInterface(IPropertiesHolder.class);
         gen.addClassForImport(Map.class);
         gen.addPluralFetchedField("Map<String, Material>", Map.class.getName(),
                 "materialProperties", "Material Properties",
                 MaterialFetchOptions.class).withInterface(IMaterialPropertiesHolder.class);
-        gen.addPluralFetchedField("Map<String, Sample>", Map.class.getName(), "sampleProperties",
+        gen.addPluralFetchedField("Map<String, Sample[]>", Map.class.getName(), "sampleProperties",
                 "Sample Properties",
                 SampleFetchOptions.class);
         gen.addClassForImport(Map.class);
@@ -143,21 +140,6 @@ public class AbstractGenerator
         gen.addClassForImport(Material.class);
         gen.addClassForImport(Sample.class);
 
-        gen.addAdditionalMethod("@Override\n"
-                + "    public String getProperty(String propertyName)\n"
-                + "    {\n"
-                + "        return getProperties() != null ? getProperties().get(propertyName) : null;\n"
-                + "    }");
-
-        gen.addAdditionalMethod("@Override\n"
-                + "    public void setProperty(String propertyName, String propertyValue)\n"
-                + "    {\n"
-                + "        if (properties == null)\n"
-                + "        {\n"
-                + "            properties = new HashMap<String, String>();\n"
-                + "        }\n"
-                + "        properties.put(propertyName, propertyValue);\n"
-                + "    }");
 
         gen.addAdditionalMethod("@Override\n"
                 + "    public Material getMaterialProperty(String propertyName)\n"
@@ -175,189 +157,7 @@ public class AbstractGenerator
                 + "        materialProperties.put(propertyName, propertyValue);\n"
                 + "    }");
 
-        gen.addClassForImport(Objects.class);
-        gen.addClassForImport(ZonedDateTime.class);
-        gen.addClassForImport(DateTimeFormatter.class);
-        gen.addClassForImport(Arrays.class);
-
-        // Integer
-        gen.addAdditionalMethod(
-                addPlaceholderTypedGetProperty("Long", "getIntegerProperty", "",
-                        "Long.parseLong(propertyValue)"));
-        gen.addAdditionalMethod(
-                addPlaceholderTypedSetProperty("Long", "setIntegerProperty", "",
-                        "Objects.toString(propertyValue, null)"));
-
-        // Varchar
-        gen.addAdditionalMethod("@Override\n"
-                + "    public String getVarcharProperty(String propertyName)\n"
-                + "    {\n"
-                + "        return getProperty(propertyName);\n"
-                + "    }");
-
-        gen.addAdditionalMethod("@Override\n"
-                + "    public void setVarcharProperty(String propertyName, String propertyValue)\n"
-                + "    {\n"
-                + "        setProperty(propertyName, propertyValue);\n"
-                + "    }");
-
-        // Multiline Varchar
-        gen.addAdditionalMethod("@Override\n"
-                + "    public String getMultilineVarcharProperty(String propertyName)\n"
-                + "    {\n"
-                + "        return getProperty(propertyName);\n"
-                + "    }");
-
-        gen.addAdditionalMethod("@Override\n"
-                + "    public void setMultilineVarcharProperty(String propertyName, String propertyValue)\n"
-                + "    {\n"
-                + "        setProperty(propertyName, propertyValue);\n"
-                + "    }");
-
-        // Real
-        gen.addAdditionalMethod(
-                addPlaceholderTypedGetProperty("Double", "getRealProperty", "",
-                        "Double.parseDouble(propertyValue)"));
-        gen.addAdditionalMethod(
-                addPlaceholderTypedSetProperty("Double", "setRealProperty", "",
-                        "Objects.toString(propertyValue, null)"));
-
-        // Timestamp
-        gen.addAdditionalMethod("@Override\n"
-                + "    public ZonedDateTime getTimestampProperty(String propertyName)\n"
-                + "    {\n"
-                + "        String propertyValue = getProperty(propertyName);\n"
-                + "        return propertyValue == null ? null : ZonedDateTime.parse(getProperty(propertyName));\n"
-                + "    }");
-
-        gen.addAdditionalMethod("@Override\n"
-                + "    public void setTimestampProperty(String propertyName, ZonedDateTime propertyValue)\n"
-                + "    {\n"
-                + "        String value = (propertyValue == null) ? null : propertyValue.format(DateTimeFormatter.ofPattern(\"yyyy-MM-dd HH:mm:ssX\"));\n"
-                + "        setProperty(propertyName, value);\n"
-                + "    }");
-
-
-        // Boolean
-        gen.addAdditionalMethod(
-                addPlaceholderTypedGetProperty("Boolean", "getBooleanProperty", "",
-                        "Boolean.parseBoolean(propertyValue)"));
-        gen.addAdditionalMethod(
-                addPlaceholderTypedSetProperty("Boolean", "setBooleanProperty", "",
-                        "Objects.toString(propertyValue, null)"));
-
-
-        // Controlled Vocabulary
-        gen.addAdditionalMethod("@Override\n"
-                + "    public String getControlledVocabularyProperty(String propertyName)\n"
-                + "    {\n"
-                + "        return getProperty(propertyName);\n"
-                + "    }");
-
-        gen.addAdditionalMethod("@Override\n"
-                + "    public void setControlledVocabularyProperty(String propertyName, String propertyValue)\n"
-                + "    {\n"
-                + "        setProperty(propertyName, propertyValue);\n"
-                + "    }");
-
-        // Sample
-        gen.addAdditionalMethod("@Override\n"
-                + "    public SamplePermId getSampleProperty(String propertyName)\n"
-                + "    {\n"
-                + "        String propertyValue = getProperty(propertyName);\n"
-                + "        return (propertyValue == null || propertyValue.trim().isEmpty()) ? null : new SamplePermId(propertyValue);\n"
-                + "    }");
-
-        gen.addAdditionalMethod("@Override\n"
-                + "    public void setSampleProperty(String propertyName, SamplePermId propertyValue)\n"
-                + "    {\n"
-                + "        setProperty(propertyName, propertyValue == null ? null : propertyValue.getPermId());\n"
-                + "    }");
-
-        // Hyperlink
-        gen.addAdditionalMethod("@Override\n"
-                + "    public String getHyperlinkProperty(String propertyName)\n"
-                + "    {\n"
-                + "        return getProperty(propertyName);\n"
-                + "    }");
-
-        gen.addAdditionalMethod("@Override\n"
-                + "    public void setHyperlinkProperty(String propertyName, String propertyValue)\n"
-                + "    {\n"
-                + "        setProperty(propertyName, propertyValue);\n"
-                + "    }");
-
-        // Xml
-        gen.addAdditionalMethod("@Override\n"
-                + "    public String getXmlProperty(String propertyName)\n"
-                + "    {\n"
-                + "        return getProperty(propertyName);\n"
-                + "    }");
-
-        gen.addAdditionalMethod("@Override\n"
-                + "    public void setXmlProperty(String propertyName, String propertyValue)\n"
-                + "    {\n"
-                + "        setProperty(propertyName, propertyValue);\n"
-                + "    }");
-
-        // Integer array
-        gen.addAdditionalMethod(
-                addPlaceholderTypedGetProperty("Long[]", "getIntegerArrayProperty", "",
-                        "Arrays.stream(propertyValue.split(\",\")).map(String::trim).map(Long::parseLong).toArray(Long[]::new)"));
-        gen.addAdditionalMethod(
-                addPlaceholderTypedSetProperty("Long[]", "setIntegerArrayProperty", "",
-                        "propertyValue == null ? null : Arrays.stream(propertyValue).map(Object::toString).reduce((a,b) -> a + \", \" + b).get()"));
-
-        // Real array
-        gen.addAdditionalMethod(
-                addPlaceholderTypedGetProperty("Double[]", "getRealArrayProperty", "",
-                        "Arrays.stream(propertyValue.split(\",\")).map(String::trim).map(Double::parseDouble).toArray(Double[]::new)"));
-        gen.addAdditionalMethod(
-                addPlaceholderTypedSetProperty("Double[]", "setRealArrayProperty", "",
-                        "propertyValue == null ? null : Arrays.stream(propertyValue).map(Object::toString).reduce((a,b) -> a + \", \" + b).get()"));
-
-        // String array
-        gen.addAdditionalMethod(
-                addPlaceholderTypedGetProperty("String[]", "getStringArrayProperty", "",
-                        "Arrays.stream(propertyValue.split(\",\")).map(String::trim).toArray(String[]::new)"));
-        gen.addAdditionalMethod(
-                addPlaceholderTypedSetProperty("String[]", "setStringArrayProperty", "",
-                        "propertyValue == null ? null : Arrays.stream(propertyValue).reduce((a,b) -> a + \", \" + b).get()"));
-
-
-        // Timestamp array
-        gen.addAdditionalMethod("@Override\n"
-                + "    public ZonedDateTime[] getTimestampArrayProperty(String propertyName)\n"
-                + "    {\n"
-                + "        String propertyValue = getProperty(propertyName);\n"
-                + "        return propertyValue == null ? null : Arrays.stream(propertyValue.split(\",\"))\n"
-                + "             .map(String::trim)\n"
-                + "             .map(dateTime -> ZonedDateTime.parse(dateTime, DateTimeFormatter.ofPattern(\"yyyy-MM-dd HH:mm:ss X\")))\n"
-                + "             .toArray(ZonedDateTime[]::new);\n"
-                + "    }");
 
-        gen.addAdditionalMethod("@Override\n"
-                + "    public void setTimestampArrayProperty(String propertyName, ZonedDateTime[] propertyValue)\n"
-                + "    {\n"
-                + "        String value = (propertyValue == null) ? null : Arrays.stream(propertyValue)\n"
-                + "                 .map(dateTime -> dateTime.format(DateTimeFormatter.ofPattern(\"yyyy-MM-dd HH:mm:ssX\")))\n"
-                + "                 .reduce((a,b) -> a + \", \" + b)\n"
-                + "                 .get();\n"
-                + "        setProperty(propertyName, value);\n"
-                + "    }");
-
-        // Json
-        gen.addAdditionalMethod("@Override\n"
-                + "    public String getJsonProperty(String propertyName)\n"
-                + "    {\n"
-                + "        return getProperty(propertyName);\n"
-                + "    }");
-
-        gen.addAdditionalMethod("@Override\n"
-                + "    public void setJsonProperty(String propertyName, String propertyValue)\n"
-                + "    {\n"
-                + "        setProperty(propertyName, propertyValue);\n"
-                + "    }");
     }
 
     private static String addPlaceholderTypedGetProperty(String type, String methodName,
diff --git a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/generators/DtoGenerator.java b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/generators/DtoGenerator.java
index e9b9cb0c27d44b760190afa2953818785381e6f1..9f5b8f28d8cf69597a80ac4c68af7568667db937 100644
--- a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/generators/DtoGenerator.java
+++ b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/generators/DtoGenerator.java
@@ -60,10 +60,14 @@ public class DtoGenerator
 
     private String toStringContent;
 
+    private String extendsClass;
+
     private Set<String> implementedInterfaces;
 
     private boolean deprecated;
 
+    private DTOField fetchOptionsField;
+
     public DtoGenerator(String subPackage, String className, Class<?> fetchOptionsClass)
     {
         this.subPackage = subPackage;
@@ -80,7 +84,7 @@ public class DtoGenerator
         addClassForImport(NotFetchedException.class);
 
         this.fetchOptionsClass = fetchOptionsClass;
-        addSimpleField(fetchOptionsClass, "fetchOptions");
+        fetchOptionsField = addSimpleField(fetchOptionsClass, "fetchOptions");
     }
 
     @Override
@@ -89,6 +93,11 @@ public class DtoGenerator
         return className;
     }
 
+    public DTOField getFetchOptionsField()
+    {
+        return fetchOptionsField;
+    }
+
     private DTOField create(String fieldName, Class<?> fieldClass, String description,
             Class<?> fetchOptions, String fetchOptionsFieldName)
     {
@@ -127,6 +136,11 @@ public class DtoGenerator
 
         boolean deprecated;
 
+        String customSetter;
+        String customGetter;
+
+        boolean isInherited = false;
+
         private DTOField(String fieldName, Class<?> fieldClass, String description,
                 Class<?> fetchOptions, String fetchOptionsFieldName,
                 boolean plural)
@@ -188,6 +202,14 @@ public class DtoGenerator
             interfaceClass = i;
         }
 
+        void withCustomGetter(String getter) {
+            customGetter = getter;
+        }
+
+        void withCustomSetter(String setter) {
+            customSetter = setter;
+        }
+
         DTOField deprecated()
         {
             deprecated = true;
@@ -300,6 +322,10 @@ public class DtoGenerator
         additionalImports.add(i.getName());
     }
 
+    public void addExtendsClass(String className) {
+        this.extendsClass = className;
+    }
+
     public DtoGenerator deprecated()
     {
         deprecated = true;
@@ -378,7 +404,7 @@ public class DtoGenerator
         printPackage(subPackage);
         printImports();
 
-        printClassHeader(className, subPackage, null, implementedInterfaces);
+        printClassHeader(className, subPackage, extendsClass, implementedInterfaces);
         startBlock();
         printFields();
 
@@ -403,7 +429,7 @@ public class DtoGenerator
     public void generateFetchOptions() throws FileNotFoundException
     {
         generateFetchOptions(
-                "/home/alaskowski/openbis/api-openbis-java/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/" + subPackage.replaceAll(
+                "../api-openbis-java/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/" + subPackage.replaceAll(
                         "\\.", "/")
                         + "/fetchoptions/" + className + "FetchOptions.java");
     }
@@ -411,7 +437,7 @@ public class DtoGenerator
     public void generateFetchOptionsJS() throws FileNotFoundException
     {
         generateFetchOptionsJS(
-                "/home/alaskowski/openbis/test-api-openbis-javascript/servers/common/core-plugins/tests/1/as/webapps/openbis-v3-api-test/html/dto/" + className
+                "../test-api-openbis-javascript/servers/common/core-plugins/tests/1/as/webapps/openbis-v3-api-test/html/dto/" + className
                         + "FetchOptions.js");
     }
 
@@ -505,15 +531,28 @@ public class DtoGenerator
 
     private void printAccessors(DTOField field)
     {
-        if (field.fetchOptions != null)
+
+        if(field.customGetter != null)
         {
-            printGetterWithFetchOptions(field);
+            print(field.customGetter);
         } else
         {
-            printBasicGetter(field);
+            if (field.fetchOptions != null)
+            {
+                printGetterWithFetchOptions(field);
+            } else
+            {
+                printBasicGetter(field);
+            }
         }
 
-        printBasicSetter(field);
+        if(field.customSetter != null)
+        {
+            print(field.customSetter);
+        } else
+        {
+            printBasicSetter(field);
+        }
     }
 
     private void printAccessorsJS(DTOField field)
@@ -824,7 +863,10 @@ public class DtoGenerator
         print("");
         for (DTOField field : fields)
         {
-            printField(field);
+            if(!field.isInherited)
+            {
+                printField(field);
+            }
         }
     }
 
diff --git a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/generators/Generator.java b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/generators/Generator.java
index 0e3199685d15b4f4d8fecfe0368cbb97da32fb60..7b52885fb2d98f0d899bcaa64a9fe5ec26a75803 100644
--- a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/generators/Generator.java
+++ b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/generators/Generator.java
@@ -21,6 +21,7 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.entity.AbstractEntity;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.attachment.Attachment;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.attachment.fetchoptions.AttachmentFetchOptions;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.Relationship;
@@ -154,6 +155,7 @@ public class Generator extends AbstractGenerator
     {
         DtoGenerator gen = new DtoGenerator("sample", "Sample", SampleFetchOptions.class);
 
+        gen.addExtendsClass("AbstractEntity<Sample>");
         addPermId(gen, SamplePermId.class);
         gen.addSimpleField(SampleIdentifier.class, "identifier").withInterface(IIdentifierHolder.class);
         addCode(gen);
@@ -164,6 +166,20 @@ public class Generator extends AbstractGenerator
         gen.addSimpleField(boolean.class, "frozenForParents");
         gen.addSimpleField(boolean.class, "frozenForDataSets");
 
+        DTOField fetchOptionField = gen.getFetchOptionsField();
+        fetchOptionField.isInherited = true;
+        fetchOptionField.withCustomSetter("public void setFetchOptions(SampleFetchOptions fetchOptions)\n" +
+                "    {\n" +
+                "        super.setFetchOptions(fetchOptions);\n" +
+                "    }\n");
+
+        fetchOptionField.withCustomGetter("@JsonIgnore\n" +
+                "    @Override\n" +
+                "    public SampleFetchOptions getFetchOptions()\n" +
+                "    {\n" +
+                "        return (SampleFetchOptions) super.getFetchOptions();\n" +
+                "    }\n");
+
         addRegistrationDate(gen);
         addModificationDate(gen);
 
@@ -173,6 +189,7 @@ public class Generator extends AbstractGenerator
         addExperiment(gen);
         addProperties(gen);
 
+        gen.addClassForImport(AbstractEntity.class);
         gen.addClassForImport(ISampleId.class);
         gen.addClassForImport(Relationship.class);
 
@@ -300,11 +317,27 @@ public class Generator extends AbstractGenerator
     private static DtoGenerator createExperimentGenerator()
     {
         DtoGenerator gen = new DtoGenerator("experiment", "Experiment", ExperimentFetchOptions.class);
+        gen.addExtendsClass("AbstractEntity<Experiment>");
 
         addPermId(gen, ExperimentPermId.class);
         gen.addSimpleField(ExperimentIdentifier.class, "identifier").withInterface(IIdentifierHolder.class);
         addCode(gen);
 
+        DTOField fetchOptionField = gen.getFetchOptionsField();
+        fetchOptionField.isInherited = true;
+        fetchOptionField.withCustomSetter("public void setFetchOptions(ExperimentFetchOptions fetchOptions)\n" +
+                "    {\n" +
+                "        super.setFetchOptions(fetchOptions);\n" +
+                "    }\n");
+
+        fetchOptionField.withCustomGetter("@JsonIgnore\n" +
+                "    @Override\n" +
+                "    public ExperimentFetchOptions getFetchOptions()\n" +
+                "    {\n" +
+                "        return (ExperimentFetchOptions) super.getFetchOptions();\n" +
+                "    }\n");
+        gen.addClassForImport(AbstractEntity.class);
+
         gen.addSimpleField(boolean.class, "frozen");
         gen.addSimpleField(boolean.class, "frozenForDataSets");
         gen.addSimpleField(boolean.class, "frozenForSamples");
@@ -370,9 +403,25 @@ public class Generator extends AbstractGenerator
     {
         DtoGenerator gen = new DtoGenerator("dataset", "DataSet", DataSetFetchOptions.class);
 
+        gen.addExtendsClass("AbstractEntity<DataSet>");
         addPermId(gen, DataSetPermId.class);
         addCode(gen);
 
+        DTOField fetchOptionField = gen.getFetchOptionsField();
+        fetchOptionField.isInherited = true;
+        fetchOptionField.withCustomSetter("public void setFetchOptions(DataSetFetchOptions fetchOptions)\n" +
+                "    {\n" +
+                "        super.setFetchOptions(fetchOptions);\n" +
+                "    }\n");
+
+        fetchOptionField.withCustomGetter("@JsonIgnore\n" +
+                "    @Override\n" +
+                "    public DataSetFetchOptions getFetchOptions()\n" +
+                "    {\n" +
+                "        return (DataSetFetchOptions) super.getFetchOptions();\n" +
+                "    }\n");
+        gen.addClassForImport(AbstractEntity.class);
+
         gen.addSimpleField(boolean.class, "frozen");
         gen.addSimpleField(boolean.class, "frozenForChildren");
         gen.addSimpleField(boolean.class, "frozenForParents");