diff --git a/gulpfile.helper.js b/gulpfile.helper.js
index 7bddd86cf4d55323201993c4e5774e8823b20a37..743deabb8a3a37aad814425d3502cd247de40e5b 100644
--- a/gulpfile.helper.js
+++ b/gulpfile.helper.js
@@ -91,7 +91,6 @@ module.exports = function (gulp, helperOptions) {
     var browserify = require('browserify')
     var source = require('vinyl-source-stream')
     var buffer = require('vinyl-buffer')
-
     return browserify({
       entries: files.specs,
       debug: true
diff --git a/src/Database.js b/src/Database.js
index fe9f3eb674a087f0d5efbd12db417550c9ebe6ae..16d23314af29627926505261cc7bc444c634a855 100644
--- a/src/Database.js
+++ b/src/Database.js
@@ -224,6 +224,9 @@ module.exports = function (Y /* :any */) {
         var o = ops[i]
         if (o.id == null || o.id[0] !== this.y.connector.userId) {
           var required = Y.Struct[o.struct].requiredOps(o)
+          if (o.requires != null) {
+            required = required.concat(o.requires)
+          }
           this.whenOperationsExist(required, o)
         }
       }
@@ -372,7 +375,7 @@ module.exports = function (Y /* :any */) {
         }
 
         // notify parent, if it was instanciated as a custom type
-        if (t != null) {
+        if (t != null && opIsDeleted) {
           yield* t._changed(transaction, Y.utils.copyObject(op))
         }
       }
diff --git a/src/SpecHelper.js b/src/SpecHelper.js
index cce99c5a571dd9652bee29897821974238aa64fb..a78f73bee7e5291136a098dc1e995e674496577a 100644
--- a/src/SpecHelper.js
+++ b/src/SpecHelper.js
@@ -25,7 +25,7 @@ g.g = g
 
 g.YConcurrency_TestingMode = true
 
-jasmine.DEFAULT_TIMEOUT_INTERVAL = 100000
+jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000
 
 g.describeManyTimes = function describeManyTimes (times, name, f) {
   for (var i = 0; i < times; i++) {
@@ -221,15 +221,18 @@ g.compareAllUsers = async(function * compareAllUsers (users) {
       // TODO: make requestTransaction return a promise..
       u.db.requestTransaction(function * () {
         yield* t2.call(this)
-        expect(s1).toEqual(s2)
-        expect(allDels1).toEqual(allDels2) // inner structure
-        expect(ds1).toEqual(ds2) // exported structure
-        var count = 0
+        var db2 = []
         yield* this.os.iterate(this, null, null, function * (o) {
           o = Y.utils.copyObject(o)
           delete o.origin
           delete o.originOf
-          expect(db1[count++]).toEqual(o)
+          db2.push(o)
+        })
+        expect(s1).toEqual(s2)
+        expect(allDels1).toEqual(allDels2) // inner structure
+        expect(ds1).toEqual(ds2) // exported structure
+        db2.forEach((o, i) => {
+          expect(db1[i]).toEqual(o)
         })
       })
     }
@@ -237,7 +240,7 @@ g.compareAllUsers = async(function * compareAllUsers (users) {
   }
 })
 
-g.createUsers = async(function * createUsers (self, numberOfUsers, database) {
+g.createUsers = async(function * createUsers (self, numberOfUsers, database, initType) {
   if (Y.utils.globalRoom.users[0] != null) {
     yield Y.utils.globalRoom.flushAll()
   }
@@ -246,6 +249,7 @@ g.createUsers = async(function * createUsers (self, numberOfUsers, database) {
     Y.utils.globalRoom.users[u].y.destroy()
   }
   self.users = null
+  yield wait()
 
   var promises = []
   for (var i = 0; i < numberOfUsers; i++) {
@@ -261,7 +265,7 @@ g.createUsers = async(function * createUsers (self, numberOfUsers, database) {
         debug: false
       },
       share: {
-        root: 'Map'
+        root: initType || 'Map'
       }
     }))
   }
diff --git a/src/Struct.js b/src/Struct.js
index 7981aab3cb28707e3bb729933eb5adcb75c96171..db880cf673b34c0cb630addaf5e4603a0ae07e64 100644
--- a/src/Struct.js
+++ b/src/Struct.js
@@ -259,11 +259,18 @@ module.exports = function (Y/* :any */) {
         }
       },
       encode: function (op) {
-        return {
+        var e = {
           struct: 'List',
           id: op.id,
           type: op.type
         }
+        if (op.requires != null) {
+          e.requires = op.requires
+        }
+        if (op.info != null) {
+          e.info = op.info
+        }
+        return e
       },
       requiredOps: function () {
         /*
@@ -332,12 +339,19 @@ module.exports = function (Y/* :any */) {
         }
       },
       encode: function (op) {
-        return {
+        var e = {
           struct: 'Map',
           type: op.type,
           id: op.id,
           map: {} // overwrite map!!
         }
+        if (op.requires != null) {
+          e.requires = op.requires
+        }
+        if (op.info != null) {
+          e.info = op.info
+        }
+        return e
       },
       requiredOps: function () {
         return []
diff --git a/src/Transaction.js b/src/Transaction.js
index a29a96ce4124a80038685162906653a474616be3..6d354184bb2c63caeedbec11ca17b6243c3a5d84 100644
--- a/src/Transaction.js
+++ b/src/Transaction.js
@@ -87,25 +87,28 @@ module.exports = function (Y/* :any */) {
       If it does not exist yes, create it.
       TODO: delete type from store.initializedTypes[id] when corresponding id was deleted!
     */
-    * getType (id) {
+    * getType (id, args) {
       var sid = JSON.stringify(id)
       var t = this.store.initializedTypes[sid]
       if (t == null) {
         var op/* :MapStruct | ListStruct */ = yield* this.getOperation(id)
         if (op != null) {
-          t = yield* Y[op.type].initType.call(this, this.store, op)
+          t = yield* Y[op.type].typeDefinition.initType.call(this, this.store, op, args)
           this.store.initializedTypes[sid] = t
         }
       }
       return t
     }
     * createType (typedefinition, id) {
-      var structname = typedefinition.struct
+      var structname = typedefinition[0].struct
       id = id || this.store.getNextOpId()
       var op = Y.Struct[structname].create(id)
-      op.type = typedefinition.name
+      op.type = typedefinition[0].name
+      if (typedefinition[0].appendAdditionalInfo != null) {
+        yield* typedefinition[0].appendAdditionalInfo.call(this, op, typedefinition[1])
+      }
       yield* this.applyCreatedOperations([op])
-      return yield* this.getType(id)
+      return yield* this.getType(id, typedefinition[1])
     }
     /*
       Apply operations that this user created (no remote ones!)
@@ -117,7 +120,7 @@ module.exports = function (Y/* :any */) {
       for (var i = 0; i < ops.length; i++) {
         var op = ops[i]
         yield* this.store.tryExecute.call(this, op)
-        if (op.id == null || op.id[0] !== '_') {
+        if (op.id == null || typeof op.id[1] !== 'string') {
           send.push(Y.Struct[op.struct].encode(op))
         }
       }
@@ -643,7 +646,7 @@ module.exports = function (Y/* :any */) {
     }
     * addOperation (op) {
       yield* this.os.put(op)
-      if (!this.store.y.connector.isDisconnected() && this.store.forwardAppliedOperations && op.id[0] !== '_') {
+      if (!this.store.y.connector.isDisconnected() && this.store.forwardAppliedOperations && typeof op.id[1] !== 'string') {
         // is connected, and this is not going to be send in addOperation
         this.store.y.connector.broadcastOps([op])
       }
@@ -653,12 +656,13 @@ module.exports = function (Y/* :any */) {
       if (o != null || id[0] !== '_') {
         return o
       } else {
-        // generate this operation?
+      /*  // generate this operation?
         if (typeof id[1] === 'string') {
           var comp = id[1].split('_')
-          if (comp.length > 1) {
+          if (comp.length > 2 || id[0] === '_') {
             var struct = comp[0]
             var op = Y.Struct[struct].create(id)
+            op.type = comp[1]
             yield* this.setOperation(op)
             return op
           } else {
@@ -668,9 +672,8 @@ module.exports = function (Y/* :any */) {
             return null
           }
         } else {
-          // Can only generate one operation at a time
-          return null
-        }
+        */
+        return null
       }
     }
     * removeOperation (id) {
diff --git a/src/Utils.js b/src/Utils.js
index c0a0cc2c05b1f4adee9539e9126c6bbe1bad5001..a45469dda3b78d2b581a5a34d0f4817adfbfbddf 100644
--- a/src/Utils.js
+++ b/src/Utils.js
@@ -26,7 +26,40 @@
 module.exports = function (Y /* : any*/) {
   Y.utils = {}
 
-  class EventHandler {
+  class EventListenerHandler {
+    constructor () {
+      this.eventListeners = []
+    }
+    destroy () {
+      this.eventListeners = null
+    }
+     /*
+      Basic event listener boilerplate...
+    */
+    addEventListener (f) {
+      this.eventListeners.push(f)
+    }
+    removeEventListener (f) {
+      this.eventListeners = this.eventListeners.filter(function (g) {
+        return f !== g
+      })
+    }
+    removeAllEventListeners () {
+      this.eventListeners = []
+    }
+    callEventListeners (event) {
+      for (var i = 0; i < this.eventListeners.length; i++) {
+        try {
+          this.eventListeners[i](event)
+        } catch (e) {
+          console.error('User events must not throw Errors!')
+        }
+      }
+    }
+  }
+  Y.utils.EventListenerHandler = EventListenerHandler
+
+  class EventHandler extends EventListenerHandler {
     /* ::
     waiting: Array<Insertion | Deletion>;
     awaiting: number;
@@ -41,16 +74,16 @@ module.exports = function (Y /* : any*/) {
       all prematurely called operations were executed ("waiting operations")
     */
     constructor (onevent /* : Function */) {
+      super()
       this.waiting = []
       this.awaiting = 0
       this.onevent = onevent
-      this.eventListeners = []
     }
     destroy () {
+      super.destroy()
       this.waiting = null
       this.awaiting = null
       this.onevent = null
-      this.eventListeners = null
     }
     /*
       Call this when a new operation arrives. It will be executed right away if
@@ -72,30 +105,6 @@ module.exports = function (Y /* : any*/) {
       this.awaiting++
       this.onevent(ops)
     }
-    /*
-      Basic event listener boilerplate...
-      TODO: maybe put this in a different type..
-    */
-    addEventListener (f) {
-      this.eventListeners.push(f)
-    }
-    removeEventListener (f) {
-      this.eventListeners = this.eventListeners.filter(function (g) {
-        return f !== g
-      })
-    }
-    removeAllEventListeners () {
-      this.eventListeners = []
-    }
-    callEventListeners (event) {
-      for (var i = 0; i < this.eventListeners.length; i++) {
-        try {
-          this.eventListeners[i](event)
-        } catch (e) {
-          console.log('User events must not throw Errors!') // eslint-disable-line
-        }
-      }
-    }
     /*
       Call this when you successfully awaited the execution of n Insert operations
     */
@@ -192,10 +201,26 @@ module.exports = function (Y /* : any*/) {
       this.initType = def.initType
       this.class = def.class
       this.name = def.name
+      if (def.appendAdditionalInfo != null) {
+        this.appendAdditionalInfo = def.appendAdditionalInfo
+      }
+      this.parseArguments = (def.parseArguments || function () {
+        return [this]
+      }).bind(this)
+      this.parseArguments.typeDefinition = this
     }
   }
   Y.utils.CustomType = CustomType
 
+  Y.utils.isTypeDefinition = function isTypeDefinition (v) {
+    if (v != null) {
+      if (v instanceof Y.utils.CustomType) return [v]
+      else if (v.constructor === Array && v[0] instanceof Y.utils.CustomType) return v
+      else if (v instanceof Function && v.typeDefinition instanceof Y.utils.CustomType) return [v.typeDefinition]
+    }
+    return false
+  }
+
   /*
     Make a flat copy of an object
     (just copy properties)
diff --git a/src/y.js b/src/y.js
index 67a5400fbe68427ce483e6537c2cac49cf348d25..58d9173791d4327a2ba3bc55da11956d592688b4 100644
--- a/src/y.js
+++ b/src/y.js
@@ -14,7 +14,11 @@ module.exports = Y
 Y.requiringModules = requiringModules
 
 Y.extend = function (name, value) {
-  Y[name] = value
+  if (value instanceof Y.utils.CustomType) {
+    Y[name] = value.parseArguments
+  } else {
+    Y[name] = value
+  }
   if (requiringModules[name] != null) {
     requiringModules[name].resolve()
     delete requiringModules[name]
@@ -29,9 +33,10 @@ function requestModules (modules) {
   var extention = typeof regeneratorRuntime !== 'undefined' ? '.js' : '.es6'
   var promises = []
   for (var i = 0; i < modules.length; i++) {
-    var modulename = 'y-' + modules[i].toLowerCase()
-    if (Y[modules[i]] == null) {
-      if (requiringModules[modules[i]] == null) {
+    var module = modules[i].split('(')[0]
+    var modulename = 'y-' + module.toLowerCase()
+    if (Y[module] == null) {
+      if (requiringModules[module] == null) {
         // module does not exist
         if (typeof window !== 'undefined' && window.Y !== 'undefined') {
           var imported = document.createElement('script')
@@ -39,7 +44,7 @@ function requestModules (modules) {
           document.head.appendChild(imported)
 
           let requireModule = {}
-          requiringModules[modules[i]] = requireModule
+          requiringModules[module] = requireModule
           requireModule.promise = new Promise(function (resolve) {
             requireModule.resolve = resolve
           })
@@ -130,15 +135,19 @@ class YConfig {
     this.db.requestTransaction(function * requestTransaction () {
       // create shared object
       for (var propertyname in opts.share) {
-        var typename = opts.share[propertyname]
-        var id = ['_', Y[typename].struct + '_' + propertyname]
-        var op = yield* this.getOperation(id)
-        if (op.type !== typename) {
-          // not already in the db
-          op.type = typename
-          yield* this.setOperation(op)
+        var typeConstructor = opts.share[propertyname].split('(')
+        var typeName = typeConstructor.splice(0, 1)
+        var args = []
+        if (typeConstructor.length === 1) {
+          try {
+            args = JSON.parse('[' + typeConstructor[0].split(')')[0] + ']')
+          } catch (e) {
+            throw new Error('Was not able to parse type definition! (share.' + propertyname + ')')
+          }
         }
-        share[propertyname] = yield* this.getType(id)
+        var id = ['_', propertyname + '_' + typeConstructor]
+        var type = Y[typeName]
+        share[propertyname] = yield* this.createType(type.apply(type.typeDefinition, args), id)
       }
       this.store.whenTransactionsFinished()
         .then(callback)