diff --git a/test_typedcols.py b/test_typedcols.py
index c9f845e1c04d067f3b802507d14c960b1a444482..03baef57268fbdf76762a349b250350c8e2d987a 100755
--- a/test_typedcols.py
+++ b/test_typedcols.py
@@ -4,37 +4,54 @@
 # Copyright (c) 2016, CESNET, z. s. p. o.
 # Use of this source is governed by an ISC license, see LICENSE file.
 
-from typedcols import TypedDict, TypedList, KeyNotAllowed, KeysRequired, Discard, Any
+from typedcols import TypedDict, OpenTypedDict, TypedList, KeyNotAllowed, KeysRequired, Discard, Any
 from sys import version_info
 import unittest
 
+address_typedef = {
+    "street": {"type": str},
+    "num": {"type": int, "description": "Street number"},
+    "city": str,
+    "state": {"type": str, "required": True}
+}
 
 class AddressDict(TypedDict):
-    typedef = {
-        "street": {"type": str},
-        "num": {"type": int, "description": "Street number"},
-        "city": str,
-        "state": {"type": str, "required": True}
-    }
+    typedef = address_typedef
     allow_unknown = True
 
 def raise_discard(x=None):
     raise Discard
 
+person_typedef = {
+    "name": {"type": str, "default": "_Default_Value_"},
+    "age": int,
+    "address": {"type": AddressDict},
+    "tel": {"type": int, "required": True},
+    "note": {},
+    "discard1": Discard,
+    "discard2": {"type": Discard, "default": "asdf"},
+    "discard3": lambda x: Discard,
+    "discard4": raise_discard,
+    "discard_default1": {"type": Any, "default": Discard}, # Same as no default
+    "discard_default2": {"type": Any, "default": raise_discard}, # Same as no default
+}
+
+person_init_data = {
+    "age": "34",
+    "note": None,
+    "address": {
+        "street": "Vrchlikova",
+        "num": 12.3,
+        "city": "Kocourkov"
+    },
+    "discard1": "junk",
+    "discard2": "garbage",
+    "discard3": "rubbish",
+    "discard4": "scrap"
+}
+
 class PersonDict(TypedDict):
-    typedef = {
-        "name": {"type": str, "default": "_Default_Value_"},
-        "age": int,
-        "address": {"type": AddressDict},
-        "tel": {"type": int, "required": True},
-        "note": {},
-        "discard1": Discard,
-        "discard2": {"type": Discard, "default": "asdf"},
-        "discard3": lambda x: Discard,
-        "discard4": raise_discard,
-        "discard_default1": {"type": Any, "default": Discard}, # Same as no default
-        "discard_default2": {"type": Any, "default": raise_discard}, # Same as no default
-    }
+    typedef = person_typedef
     allow_unknown = False
 
 
@@ -46,19 +63,7 @@ if not hasattr(unittest.TestCase, "assertRaisesRegex"):
 class TestTypedDict(unittest.TestCase):
 
     def setUp(self):
-        self.person = PersonDict({
-            "age": "34",
-            "note": None,
-            "address": {
-                "street": "Vrchlikova",
-                "num": 12.3,
-                "city": "Kocourkov"
-            },
-            "discard1": "junk",
-            "discard2": "garbage",
-            "discard3": "rubbish",
-            "discard4": "scrap"
-        })
+        self.person = PersonDict(person_init_data)
 
     def testTypedefNormalization(self):
         self.assertEqual(self.person.typedef["age"], {"type": int})
@@ -127,6 +132,20 @@ class TestTypedDict(unittest.TestCase):
             ("note", None)
         ])
 
+
+class TestOpenTypedDict(TestTypedDict):
+
+    def setUp(self):
+        open_address_dict = OpenTypedDict(typedef=address_typedef.copy())
+
+        open_person_typedef = person_typedef.copy()
+        open_person_typedef["address"] = open_address_dict
+
+        open_person_dict = OpenTypedDict(typedef=open_person_typedef)
+
+        self.person = open_person_dict(person_init_data)
+
+
 class IntList(TypedList):
     item_type = int
 
diff --git a/typedcols.py b/typedcols.py
index 04398f27807934c5b0c60ce9340e79dc78c0d206..e61441977fb6689ddbbd76295a87600c9af87754 100644
--- a/typedcols.py
+++ b/typedcols.py
@@ -10,7 +10,7 @@ Defines TypedDict and TypedList, which enforce inserted types based on simple
 type definition.
 """
 
-__version__ = '0.1.9'
+__version__ = '0.1.10'
 __author__ = 'Pavel Kácha <pavel.kacha@cesnet.cz>'
 
 import collections
@@ -42,24 +42,26 @@ def Any(v):
     return v
 
 
+def dictify_typedef(typedef):
+    for key in typedef:
+        tdef = typedef[key]
+        if callable(tdef):
+            typedef[key] = {"type": tdef}
+        typedef[key].setdefault("type", Any)
+
+
 class TypedDictMetaclass(abc.ABCMeta):
-    """ Metaclass for TypedDict, allowing simplified typedefs - if typedef is not
-        dict, simple type object is assumed and correct dict is created.
+    """ Metaclass for TypedDict, allowing simplified typedefs - if typedef is
+        callable, simple type object is assumed and correct dict is created.
         Metaclassed to be run just once for the class, not for each instance.
     """
 
-    def dictifyTypedef(self, typedef):
-        for key in typedef:
-            tdef = typedef[key]
-            if not isinstance(tdef, collections.Mapping):
-                typedef[key] = {"type": tdef}
-
     def __init__(cls, name, bases, dct):
         super(TypedDictMetaclass, cls).__init__(name, bases, dct)
-        cls.dictifyTypedef(cls.typedef)
+        dictify_typedef(cls.typedef)
 
 
-class TypedDict(collections.MutableMapping):
+class TypedDictBase(collections.MutableMapping):
     """ Dictionary type abstract class, which supports checking of inserted
         types, based on simple type definition.
 
@@ -159,7 +161,7 @@ class TypedDict(collections.MutableMapping):
             .arg will be message from "description" field in type definition
         """
         tdef = self.getTypedef(key)
-        valuetype = tdef.get("type", Any)
+        valuetype = tdef["type"]
         if valuetype is Discard:
             return
         try:
@@ -211,7 +213,70 @@ class TypedDict(collections.MutableMapping):
 # Py 2 requires metaclassing by __metaclass__ attribute, whereas Py 3
 # needs metaclass argument. What actually happens is the following,
 # so we will do it explicitly, to be compatible with both versions.
-TypedDict = TypedDictMetaclass("TypedDict", (TypedDict,), {})
+TypedDict = TypedDictMetaclass("TypedDict", (TypedDictBase,), {})
+
+
+class TypedefSetter(object):
+    """ Setter for OpenTypedDict.typedef value, which forces typedef canonicalisation.
+        Implemented as setter only class, as it does not intercept and slow down read
+        access.
+    """
+
+    def __set__(self, obj, value):
+        dictify_typedef(value)
+        obj.__dict__["typedef"] = value
+
+
+class OpenTypedDict(TypedDictBase):
+    """ Dictionary type class, which supports checking of inserted types, based on
+        simple type definition, which must be provided in constructor and is changeable
+        by assigning instance.typedef variable.
+
+        Note however that changing already populated OpenTypedDict's typedef to
+        incompatible definition may lead to undefined results and data inconsistent
+        with definition.
+    """
+
+    def __init__(self, init_data=None, typedef=None, allow_unknown=False, dict_class=dict):
+        """ init_data: initial values
+
+            typedef: dictionary with keys and their type definitions. Type definition
+                may be simple callable (int, string, check_func,
+                AnotherTypedDict), or dict with the following members:
+                    "type":
+                        type enforcing callable. If callable returns, raises
+                        or is Discard, key will be silently discarded
+                    "default":
+                        new TypedDict subclass will be initialized with keys
+                        with this value; deleted keys will also revert to it
+                    "required":
+                        bool, checkRequired method will report the key if not present
+                    "description":
+                        string, explaining field type in human readable terms
+                        (will be used in exception explanations)
+                Type enforcing callable must take one argument, and return value,
+                coerced to expected type. Coercion may even be conversion, for example
+                arbitrary date string, converted to DateTime.
+
+            allow_unknown: boolean, specifies whether dictionary allows unknown keys,
+                that means keys, which are not defined in 'typedef'
+
+            dict_class: class or factory for underlying dict implementation
+        """
+        self.allow_unknown = allow_unknown
+        self.dict_class = dict_class
+        self.typedef = typedef or {}
+        super(OpenTypedDict, self).__init__(init_data)
+
+    typedef = TypedefSetter()
+
+    def __call__(self, data):
+        """ Instances are made callable so they can be used in nested "type"
+            definitions. Note however that these classes are mutable, so
+            assigning new values replaces old ones.
+        """
+        self.update(data)
+        return self
 
 
 class TypedList(collections.MutableSequence):