diff --git a/api-openbis-java/build.gradle b/api-openbis-java/build.gradle
index 6b1280153471a3baa8f6e88934db6acbafda656b..fd43ab44e1a4dcefba6bf5866d6138c737508712 100644
--- a/api-openbis-java/build.gradle
+++ b/api-openbis-java/build.gradle
@@ -63,21 +63,11 @@ apply plugin: "cz.habarta.typescript-generator"
 generateTypeScript {
     jsonLibrary = 'jackson2'
     classPatterns = [
-//            'ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.**',
-//            'ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.**',
-//            'ch.ethz.sis.openbis.generic.asapi.v3.dto.property.**',
-//            'ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.**',
-//            'ch.ethz.sis.openbis.generic.asapi.v3.dto.project.**',
-//            'ch.ethz.sis.openbis.generic.asapi.v3.dto.person.**',
-//            'ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.**',
-//            'ch.ethz.sis.openbis.generic.asapi.v3.dto.material.**',
-//            'ch.ethz.sis.openbis.generic.asapi.v3.dto.space.**',
-//            'ch.ethz.sis.openbis.generic.asapi.v3.dto.common.**',
-//            'ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.**',
-//            'ch.ethz.sis.openbis.generic.OpenBIS',
-            'ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.archive.ArchiveDataSetsOperation'
-
+            'ch.ethz.sis.openbis.generic.asapi.v3.dto.**',
+            'ch.ethz.sis.openbis.generic.dssapi.v3.dto.**',
+            'ch.ethz.sis.openbis.generic.OpenBIS',
     ]
+
     excludeClassPatterns = ["**.v1.**",
                             "**.generic.shared.**",
                             "ch.ethz.sis.openbis.generic.asapi.v3.dto.session.search.PersonalAccessTokenSessionNameSearchCriteria",
diff --git a/api-openbis-java/source/java/ch/empa/tsprocessor/MethodExtension.java b/api-openbis-java/source/java/ch/empa/tsprocessor/MethodExtension.java
index 0373a80d585d3b32c4d680ad4b5cede9d53b40cf..4883f0b0ff0f29322c32b90c610b4a97bb067b3f 100644
--- a/api-openbis-java/source/java/ch/empa/tsprocessor/MethodExtension.java
+++ b/api-openbis-java/source/java/ch/empa/tsprocessor/MethodExtension.java
@@ -17,13 +17,81 @@ import java.util.stream.Stream;
 import com.fasterxml.jackson.databind.ObjectMapper;// in play 2.3
 
 interface MethodProcessor {
-    TsPropertyModel makeFunction(Method method, SymbolTable symbolTable);
+    TsPropertyModel makeFunction(Method method, TsModel model, ProcessingContext processingContext);
+}
+
+interface MakeConstructor {
+    TsConstructorModel makeConstructor(Constructor<?> constructor, TsModel model, ProcessingContext processingContext);
+}
+
+class ProcessingContext {
+    private final SymbolTable symbolTable;
+    private final MappedTypeExtractor typeExtractor;
+    private final TypeProcessor localProcessor;
+
+    ProcessingContext(SymbolTable symbolTable, MappedTypeExtractor typeExtractor, TypeProcessor localProcessor) {
+        this.symbolTable = symbolTable;
+        this.typeExtractor = typeExtractor;
+        this.localProcessor = localProcessor;
+    }
+
+    public SymbolTable getSymbolTable() {
+        return symbolTable;
+    }
+
+    public MappedTypeExtractor getTypeExtractor() {
+        return typeExtractor;
+    }
+
+    public TypeProcessor getLocalProcessor() {
+        return localProcessor;
+    }
+}
+
+class MappedTypeExtractor {
+
+    private final HashMap<Class<?>, TsType> mappedTypes = new HashMap<>();
+
+    public void extractMappedTypes(TsModel model) {
+        model.getBeans().forEach(bean -> {
+            System.out.printf("Extracting mapped types for bean %s\n", bean.getOrigin().getName());
+            Class<?> origin = bean.getOrigin();
+            Field[] fields = origin.getDeclaredFields();
+            System.out.printf("Extracting mapped types for bean %s, the fields are %s\n", bean.getOrigin().getName(), Arrays.toString(fields));
+            bean.getProperties().forEach(prop -> {
+                TsType propType = prop.tsType;
+
+                Optional<Field> originalField = Arrays.stream(fields).filter(field -> field.getName().equals(prop.getName())).findFirst();
+                Class<?> originalClass = originalField.flatMap(field -> Optional.ofNullable(field.getType())).orElse(null);
+                TsType tsType = originalClass != null ? mappedTypes.put(originalClass, propType) : null;
+            });
+            mappedTypes.put(origin, new TsType.ReferenceType(bean.getName()));
+        });
+        model.getTypeAliases().stream().forEach(tsAliasModel -> {
+            mappedTypes.put(tsAliasModel.getOrigin(), tsAliasModel.getDefinition());
+        });
+        System.out.printf("Mapped types %s\n", mappedTypes);
+
+    }
+
+    public HashMap<Class<?>, TsType> getMappedTypes() {
+        return mappedTypes;
+    }
+
+    public Optional<TsType> getMappedType(Class<?> clz) {
+        return Optional.ofNullable(mappedTypes.get(clz));
+    }
 }
 
 public class MethodExtension extends Extension {
 
     public static final String CFG_ASYNC_CLASSES = "asyncClasses";
     static final ObjectMapper mapper = new ObjectMapper();
+    private static final List<Class<?>> assignableContainers = List.of(List.class, Set.class, ArrayList.class, Collection.class, Map.class, HashMap.class, Optional.class);
+
+    private static final Logger logger = TypeScriptGenerator.getLogger();
+    //Hold types that were mapped by the bean model
+//    private final MappedTypeExtractor typeExtractor = new MappedTypeExtractor();
     private List<String> asnycClasses = new ArrayList<>();
 
     public MethodExtension() {
@@ -33,66 +101,52 @@ public class MethodExtension extends Extension {
         this.asnycClasses = asyncClasses;
     }
 
+
     private static boolean filterMethods(Method method) {
         return !((method.getDeclaringClass() == Object.class) || (method.getName().matches("hashCode|toString|equals")));
     }
 
-    private static List<TsParameter> getMethodParameters(Method method, SymbolTable symbolTable) {
-        return Arrays.stream(method.getParameters()).map(parameter -> new TsParameter(method.getName(), ResolveGenericType(parameter.getParameterizedType(), symbolTable))).collect(Collectors.toList());
-    }
-
-    private static TsType ResolveGenericType(Type type, SymbolTable symbolTable) {
-        if (type instanceof ParameterizedType) {
-            ParameterizedType parameterizedType = (ParameterizedType) type;
-            Class<?> rawType = (Class<?>) parameterizedType.getRawType();
-
-            if (List.class.isAssignableFrom(rawType)) {
-                // Manually map List<T> to Array<T>
-                TsType elementType = ResolveGenericType(parameterizedType.getActualTypeArguments()[0], symbolTable);
-                return new TsType.GenericReferenceType(symbolTable.getSymbol(Array.class), Collections.singletonList(elementType));
-            } else if (Set.class.isAssignableFrom(rawType)) {
-                // Manually map List<T> to Array<T>
-                TsType elementType = ResolveGenericType(parameterizedType.getActualTypeArguments()[0], symbolTable);
-                return new TsType.GenericReferenceType(symbolTable.getSymbol(Set.class), Collections.singletonList(elementType));
-            } else if (ArrayList.class.isAssignableFrom(rawType)) {
-                TsType elementType = ResolveGenericType(parameterizedType.getActualTypeArguments()[0], symbolTable);
-                return new TsType.GenericReferenceType(symbolTable.getSymbol(ArrayList.class), Collections.singletonList(elementType));
-            } else {
-                Class<?> rawClass = (Class<?>) parameterizedType.getRawType();
-                System.out.printf("Other type %s\n", rawClass.getName());
-                TsType[] typeArguments = Arrays.stream(parameterizedType.getActualTypeArguments()).map(typeArgument -> ResolveGenericType(typeArgument, symbolTable)).toArray(TsType[]::new);
-                return new TsType.GenericReferenceType(symbolTable.getSymbol(rawClass), Arrays.asList(typeArguments));
-            }
-        } else if (type instanceof GenericArrayType) {
-            GenericArrayType genericArrayType = (GenericArrayType) type;
-            return new TsType.BasicArrayType(ResolveGenericType(genericArrayType.getGenericComponentType(), symbolTable));
-        } else if (type instanceof Class) {
-            Class<?> clz = (Class<?>) type;
-            return new TsType.ReferenceType(symbolTable.getSymbol(clz));
-        } else if (type instanceof WildcardType) {
-            WildcardType wildcardType = (WildcardType) type;
-            final Type[] upperBounds = wildcardType.getUpperBounds();
-            return upperBounds.length > 0 ? ResolveGenericType(upperBounds[0], symbolTable) : TsType.Any;
-        } else {
-            // Handle TypeVariable case
-            return TsType.Any;
-        }
+    private static Optional<Class<?>> getAssignableClass(Class<?> clz) {
+        return assignableContainers.stream().filter(container -> container.isAssignableFrom(clz)).findFirst();
+    }
+
+    private static List<TsParameter> getMethodParameters(Executable method, TsModel model, ProcessingContext processingContext) {
+        return Arrays.stream(method.getParameters()).map(parameter -> new TsParameter(parameter.getName(), ResolveGenericType(parameter.getParameterizedType(), model, processingContext))).collect(Collectors.toList());
+    }
+
+
+    private static TsType ResolveGenericType(Type type, TsModel model, ProcessingContext processingContext) {
+
+        TypeProcessor.Context context = new TypeProcessor.Context(processingContext.getSymbolTable(), processingContext.getLocalProcessor(), null);
+        return context.processType(type).getTsType();
+
     }
 
-    private static TsType getReturnType(Method method, SymbolTable symbolTable) {
-        return ResolveGenericType(method.getGenericReturnType(), symbolTable);
+    private static TsType getReturnType(Method method, TsModel model, ProcessingContext processingContext) {
+        return ResolveGenericType(method.getGenericReturnType(), model, processingContext);
 
     }
 
-    private static TsPropertyModel makeFunction(Method method, SymbolTable symbolTable) {
-        List<TsParameter> params = getMethodParameters(method, symbolTable);
-        TsType returnType = getReturnType(method, symbolTable);
+    private static TsPropertyModel makeFunction(Method method, TsModel model, ProcessingContext processingContext) {
+        List<TsParameter> params = getMethodParameters(method, model, processingContext);
+        TsType returnType = getReturnType(method, model, processingContext);
         return new TsPropertyModel(method.getName(), new TsType.FunctionType(params, returnType), TsModifierFlags.None, false, null);
     }
 
-    private static TsPropertyModel makeCallBackFunction(Method method, SymbolTable symbolTable) {
-        List<TsParameter> params = getMethodParameters(method, symbolTable);
-        TsType returnType = getReturnType(method, symbolTable);
+    private static Optional<TsMethodModel> propertyModelToMethodModel(TsPropertyModel propertyModel) {
+        TsType value = propertyModel.getTsType();
+        if (value instanceof TsType.FunctionType) {
+            TsType.FunctionType functionType = (TsType.FunctionType) value;
+            List<TsParameterModel> params = functionType.parameters.stream().map(param -> new TsParameterModel(param.name, param.getTsType())).collect(Collectors.toList());
+            return Optional.of(new TsMethodModel(propertyModel.getName(), propertyModel.getModifiers(), null, params, functionType.type, null, null));
+        } else {
+            return Optional.empty();
+        }
+    }
+
+    private static TsPropertyModel makeCallBackFunction(Method method, TsModel model, ProcessingContext processingContext) {
+        List<TsParameter> params = getMethodParameters(method, model, processingContext);
+        TsType returnType = getReturnType(method, model, processingContext);
         TsParameter callbackParam = new TsParameter("callback", returnType);
         TsType.FunctionType arrowFunction = new TsType.FunctionType(List.of(callbackParam), TsType.Null);
         TsParameter callback = new TsParameter("callback", arrowFunction);
@@ -100,20 +154,34 @@ public class MethodExtension extends Extension {
         return new TsPropertyModel(method.getName(), new TsType.FunctionType(paramsWithCallback, TsType.Null), TsModifierFlags.None, false, null);
     }
 
-    private static TsPropertyModel makePromiseReturningFunction(Method method, SymbolTable symbolTable) {
-        List<TsParameter> params = getMethodParameters(method, symbolTable);
-        List<TsType> returnType = List.of(getReturnType(method, symbolTable));
+    private static TsPropertyModel makePromiseReturningFunction(Method method, TsModel model, ProcessingContext processingContext) {
+        List<TsParameter> params = getMethodParameters(method, model, processingContext);
+        List<TsType> returnType = List.of(getReturnType(method, model, processingContext));
         TsType promiseType = new TsType.GenericReferenceType(new Symbol("Promise"), returnType);
         return new TsPropertyModel(method.getName(), new TsType.FunctionType(params, promiseType), TsModifierFlags.None, false, null);
     }
 
-    private static TsBeanModel addFunctions(TsBeanModel bean, SymbolTable symbolTable, MethodProcessor processor) {
+    private static TsMethodModel makeConstructor(Constructor<?> constructor, TsBeanModel beanModel, TsModel model, ProcessingContext processingContext) {
+        List<TsParameter> params = getMethodParameters(constructor, model, processingContext);
+        //Exclude parameters that correspond to the bean itself
+        List<TsParameter> paramsWithoutDeclaringClass = params.stream().collect(Collectors.toList());
+        TsType returnType = ResolveGenericType(constructor.getDeclaringClass(), model, processingContext);
+        System.out.printf("Constructor %s, params %s, return type %s\n", constructor, params, returnType);
+        TsType.FunctionType functionType = new TsType.FunctionType(paramsWithoutDeclaringClass, returnType);
+        TsPropertyModel propertyModel = new TsPropertyModel("new ", functionType, TsModifierFlags.None, false, null);
+        return propertyModelToMethodModel(propertyModel).orElse(null);
+    }
+
+    private static TsBeanModel addFunctions(TsBeanModel bean, TsModel model, ProcessingContext processingContext, MethodProcessor processor) {
         Class<?> origin = bean.getOrigin();
-        Stream<TsPropertyModel> params = Arrays.stream(origin.getMethods()).filter(MethodExtension::filterMethods).map(method -> processor.makeFunction(method, symbolTable));
-        List<TsPropertyModel> allProps = Stream.concat(params, bean.getProperties().stream()).collect(Collectors.toList());
-        return bean.withProperties(allProps);
+
+        Stream<TsMethodModel> params = Arrays.stream(origin.getMethods()).filter(MethodExtension::filterMethods).map(method -> propertyModelToMethodModel(processor.makeFunction(method, model, processingContext))).flatMap(it -> it.map(Stream::of).orElse(Stream.empty()));
+        Stream<TsMethodModel> constructors = Arrays.stream(origin.getDeclaredConstructors()).map(constructor -> makeConstructor(constructor, bean, model, processingContext));
+        List<TsMethodModel> allMethods = Stream.of(params, constructors).flatMap(it -> it).collect(Collectors.toList());
+        return bean.withProperties(bean.getProperties()).withMethods(allMethods);
     }
 
+
     @Override
     public void setConfiguration(Map<String, String> configuration) throws RuntimeException {
 
@@ -142,14 +210,24 @@ public class MethodExtension extends Extension {
         return features;
     }
 
+
     @Override
     public List<TransformerDefinition> getTransformers() {
-        return List.of(new TransformerDefinition(ModelCompiler.TransformationPhase.BeforeSymbolResolution, (TsModelTransformer) (context, model) -> {
+        return List.of(new TransformerDefinition(ModelCompiler.TransformationPhase.AfterDeclarationSorting, (TsModelTransformer) (context, model) -> {
+            //Extract all types that were mapped by the bean model to reuse them
+            MappedTypeExtractor typeExtractor = new MappedTypeExtractor();
+            typeExtractor.extractMappedTypes(model);
+            String classNames = model.getBeans().stream().map(it -> it.getName().getFullName()).collect(Collectors.joining("\n"));
+            System.out.printf("model %s\n", classNames);
+            System.out.printf("Mapped types %s\n", typeExtractor.getMappedTypes());
+            TypeProcessor localProcessor = new DefaultTypeProcessor();
+            ProcessingContext processingContext = new ProcessingContext(context.getSymbolTable(), typeExtractor, localProcessor);
+            //Add table of mapped types
             Stream<TsBeanModel> processedBeans = model.getBeans().stream().map(bean -> {
                 if (asnycClasses.contains(bean.getOrigin().getName())) {
-                    return addFunctions(bean, context.getSymbolTable(), MethodExtension::makePromiseReturningFunction);
+                    return addFunctions(bean, model, processingContext, MethodExtension::makePromiseReturningFunction);
                 } else {
-                    return addFunctions(bean, context.getSymbolTable(), MethodExtension::makeFunction);
+                    return addFunctions(bean, model, processingContext, MethodExtension::makeFunction);
                 }
             });
 
diff --git a/api-openbis-java/sourceTest/java/ch/empa/tsprocessor/MethodExtensionTest.java b/api-openbis-java/sourceTest/java/ch/empa/tsprocessor/MethodExtensionTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..9c157f9f053132842ae2ea8de313de14943b98b5
--- /dev/null
+++ b/api-openbis-java/sourceTest/java/ch/empa/tsprocessor/MethodExtensionTest.java
@@ -0,0 +1,75 @@
+package ch.empa.tsprocessor;
+
+import ch.systemsx.cisd.base.annotation.JsonObject;
+import cz.habarta.typescript.generator.*;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+
+import java.util.List;
+
+public class MethodExtensionTest {
+
+    interface GenericTestClass<A> {
+        A get();
+    }
+
+    //@JsonObject("TestClass")
+    class TestClass {
+        public boolean A;
+        public String[] B;
+        public boolean getA() {return false;}
+        public String[] getB() {return null;}
+        TestClass(String a){}
+    }
+
+    class InnerTestClass {
+        public TestClass A;
+        public boolean getA() {return false;}
+    }
+
+    interface InterfaceWithWildcard {
+        interface OuterInterface{}
+
+        String doSomething(List<? extends OuterInterface> input);
+    }
+
+
+
+
+    final Settings settings = new Settings();
+    @BeforeTest
+    public void setSettings(){
+        settings.outputKind = (TypeScriptOutputKind.module);
+        settings.jsonLibrary = JsonLibrary.jackson2;
+        settings.extensions = List.of(new MethodExtension());
+    }
+
+
+
+    @Test
+    public void testGenericClass() {
+        final String output = new TypeScriptGenerator(settings).generateTypeScript(Input.from(GenericTestClass.class));
+        System.out.println(output);
+
+    }
+
+    @Test
+    public void testNormalClass(){
+        final String output = new TypeScriptGenerator(settings).generateTypeScript(Input.from(TestClass.class));
+        System.out.println(output);
+    }
+
+    @Test
+    public void testInnerClass(){
+        final String output = new TypeScriptGenerator(settings).generateTypeScript(Input.from(InnerTestClass.class));
+        System.out.println(output);
+    }
+    @Test
+    public void testWildCardType(){
+        final String output = new TypeScriptGenerator(settings).generateTypeScript(Input.from(InterfaceWithWildcard.class));
+        System.out.println(output);
+    }
+
+
+}
diff --git a/api-openbis-java/sourceTest/java/tests.xml b/api-openbis-java/sourceTest/java/tests.xml
index c4a6566e3a236af979dcd0ccb6eef992750fb69f..5fb12d925a7f64ed6153c53c7033d4fc95f0454e 100644
--- a/api-openbis-java/sourceTest/java/tests.xml
+++ b/api-openbis-java/sourceTest/java/tests.xml
@@ -8,6 +8,7 @@
     <packages>
       <package name="ch.ethz.sis.openbis.*" />
       <package name="ch.systemsx.cisd.openbis.*" />
+      <package name="ch.empa.tsprocessor.*" />
     </packages>
   </test>
 </suite>