diff --git a/goblin/__init__.py b/goblin/__init__.py
index 354f37e7ffa59c4c4ae5d3bdcd27ff95f13ff315..5be1e8bcb0dceea5e331e4f9bd4bce292186432c 100644
--- a/goblin/__init__.py
+++ b/goblin/__init__.py
@@ -15,6 +15,7 @@
 # You should have received a copy of the GNU Affero General Public License
 # along with Goblin.  If not, see <http://www.gnu.org/licenses/>.
 
-from goblin.element import Vertex, Edge, VertexProperty
 from goblin.app import create_app, Goblin
+from goblin.cardinality import Cardinality
+from goblin.element import Vertex, Edge, VertexProperty
 from goblin.properties import Property, String
diff --git a/goblin/abc.py b/goblin/abc.py
index 5abb4c9c355e3c69ce96293902bd8574fd2db370..91b8a1240ae53515643fce60540e403acdcf4359 100644
--- a/goblin/abc.py
+++ b/goblin/abc.py
@@ -16,6 +16,12 @@
 # along with Goblin.  If not, see <http://www.gnu.org/licenses/>.
 
 import abc
+import logging
+
+from goblin import cardinality, manager, exception
+
+
+logger = logging.getLogger(__name__)
 
 
 class DataType(abc.ABC):
@@ -44,35 +50,37 @@ class DataType(abc.ABC):
     @abc.abstractmethod
     def to_ogm(self, val):
         """Convert property value to a Python compatible format"""
-        try:
-            self.validate(val)
-        except exception.ValidationError:
-            logger.warning(
-                "DB val {} Fails OGM validation for {}".format(val, self))
         return val
 
-    def validate_cardinality(self, val, cardinality):
-        if cardinality:
-            if issubclass(cardinality, list):
-                if isinstance(val, list):
-                    val = val
-                elif isinstance(val, set):
-                    val = list(set)
-                else:
-                    val = [val]
-                # Check here if vertex prop
-                val = [self.validate(v) for v in val]
-            elif issubclass(cardinality, set):
-                if isinstance(val, set):
-                    val = val
-                elif isinstance(val, list):
-                    val = set(val)
-                else:
-                    val = set([val])
-                # Check here if vertex prop
-                val = {self.validate(v) for v in val }
+    def validate_vertex_prop(self, val, card, vertex_prop, data_type):
+        if card == cardinality.Cardinality.list:
+            if isinstance(val, list):
+                val = val
+            elif isinstance(val, (set, tuple)):
+                val = list(val)
+            else:
+                val = [val]
+            val = manager.ListVertexPropertyManager(
+                data_type,
+                vertex_prop,
+                card,
+                [vertex_prop(data_type, val=self.validate(v), card=card)
+                 for v in val])
+        elif card == cardinality.Cardinality.set:
+            if isinstance(val, set):
+                val = val
+            elif isinstance(val, (list, tuple)):
+                val = set(val)
+            else:
+                val = set([val])
+            val = manager.SetVertexPropertyManager(
+                data_type,
+                vertex_prop,
+                card,
+                {vertex_prop(data_type, val=self.validate(v), card=card)
+                 for v in val})
         else:
-            val = self.validate(val)
+            val = vertex_prop(data_type, val=self.validate(val))
         return val
 
 
@@ -81,7 +89,3 @@ class BaseProperty:
     @property
     def data_type(self):
         raise NotImplementedError
-
-    @property
-    def cardinality(self):
-        raise NotImplementedError
diff --git a/goblin/cardinality.py b/goblin/cardinality.py
new file mode 100644
index 0000000000000000000000000000000000000000..ce477a61af1259b0f2812f3346732cf71c3a7e65
--- /dev/null
+++ b/goblin/cardinality.py
@@ -0,0 +1,27 @@
+# Copyright 2016 ZEROFAIL
+#
+# This file is part of Goblin.
+#
+# Goblin is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Goblin is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with Goblin.  If not, see <http://www.gnu.org/licenses/>.
+
+"""Enum to handle property cardinality"""
+
+import enum
+
+
+class Cardinality(enum.Enum):
+    """Property cardinality"""
+    single = 1
+    list = 2
+    set = 3
diff --git a/goblin/element.py b/goblin/element.py
index 989663a8ce015d05c3dde829167b0ce362211f29..bc8be9a441bc43bb80acbcd047c3eaefa78f96a4 100644
--- a/goblin/element.py
+++ b/goblin/element.py
@@ -19,10 +19,7 @@ import logging
 
 import inflection
 
-from goblin import abc
-from goblin import exception
-from goblin import mapper
-from goblin import properties
+from goblin import abc, cardinality, exception, mapper, properties
 
 
 logger = logging.getLogger(__name__)
@@ -44,9 +41,9 @@ class ElementMeta(type):
         new_namespace = {}
         for k, v in namespace.items():
             if isinstance(v, abc.BaseProperty):
-                if element_type == 'edge' and v.cardinality is not None:
+                if element_type == 'edge' and hasattr(v, 'cardinality'):
                     raise exception.MappingError(
-                        'Edge property with set/list cardinality')
+                        'Edge property cannot have set/list cardinality')
                 props[k] = v
                 v = v.__descriptor__(k, v)
             new_namespace[k] = v
@@ -115,7 +112,7 @@ class GenericEdge(Edge):
     Class used to build edges when user defined edges class is not available.
     Generally not instantiated by end user.
     """
-
+    pass
 
 class VertexPropertyDescriptor:
     """
@@ -128,44 +125,41 @@ class VertexPropertyDescriptor:
         self._vertex_property = vertex_property.__class__
         self._data_type = vertex_property.data_type
         self._default = vertex_property.default
+        self._cardinality = vertex_property._cardinality
 
     def __get__(self, obj, objtype):
         if obj is None:
-            return self._vertex_property
+            return self._vertex_property  # do this like property
         default = self._default
         if default:
-            default = self._data_type.validate(default)
-            default = self._vertex_property(self._default)
+            default = self._data_type.validate_vertex_prop(
+                default, self._cardinality, self._vertex_property,
+                self._data_type)
         return getattr(obj, self._name, default)
 
     def __set__(self, obj, val):
-        if isinstance(val, (list, tuple , set)):
-            vertex_property = []
-            for v in val:
-                v = self._data_type.validate(v)
-                vertex_property.append(
-                    self._vertex_property(self._data_type, value=v))
-
-        else:
-            val = self._data_type.validate(val)
-            vertex_property = self._vertex_property(self._data_type, value=val)
-        setattr(obj, self._name, vertex_property)
+        if val:
+            val = self._data_type.validate_vertex_prop(
+                val, self._cardinality, self._vertex_property, self._data_type)
+        setattr(obj, self._name, val)
 
 
-class VertexProperty(Element, abc.BaseProperty):
+class VertexProperty(Vertex, abc.BaseProperty):
     """Base class for user defined vertex properties. Not yet supported."""
 
     __descriptor__ = VertexPropertyDescriptor
 
-    def __init__(self, data_type, *, value=None, default=None, db_name=None,
-                 cardinality=None):
+    def __init__(self, data_type, *, val=None, default=None, db_name=None,
+                 card=None):
         if isinstance(data_type, type):
             data_type = data_type()
         self._data_type = data_type
-        self._value = value
+        self._val = val
         self._default = default
         self._db_name = db_name
-        self._cardinality = cardinality
+        if card is None:
+            card = cardinality.Cardinality.single
+        self._cardinality = card
 
     @property
     def default(self):
@@ -177,7 +171,7 @@ class VertexProperty(Element, abc.BaseProperty):
 
     @property
     def value(self):
-        return self._value
+        return self._val
 
     @property
     def db_name(self):
diff --git a/goblin/manager.py b/goblin/manager.py
new file mode 100644
index 0000000000000000000000000000000000000000..9de16b6d64bbcc9e5a6cbd79a260d55dacdc694d
--- /dev/null
+++ b/goblin/manager.py
@@ -0,0 +1,43 @@
+"""Managers for multi cardinality vertex properties"""
+
+
+class VertexPropertyManager:
+
+    def __call__(self, val):
+        results = []
+        for v in self:
+            if v.value == val:
+                results.append(v)
+        if len(results) == 1:
+            results = results[0]
+        elif not results:
+            results = None
+        return results
+
+
+class ListVertexPropertyManager(list, VertexPropertyManager):
+
+    def __init__(self, data_type, vertex_prop, card, obj):
+        self._data_type = data_type
+        self._vertex_prop = vertex_prop
+        self._card = card
+        list.__init__(self, obj)
+
+    def append(self, val):
+        val = self._data_type.validate(val)
+        val = self._vertex_prop(self._data_type, val=val, card=self._card)
+        super().append(val)
+
+
+class SetVertexPropertyManager(set, VertexPropertyManager):
+
+    def __init__(self, data_type, vertex_prop, card, obj):
+        self._data_type = data_type
+        self._vertex_prop = vertex_prop
+        self._card = card
+        set.__init__(self, obj)
+
+    def add(self, val):
+        val = self._data_type.validate(val)
+        val = self._vertex_prop(self._data_type, val=val, card=self._card)
+        super().add(val)
diff --git a/goblin/mapper.py b/goblin/mapper.py
index 0a086de3511457454f46394314dbba804a94d95c..793d7851b5068db302b30599bdbbdd00c1cdd878 100644
--- a/goblin/mapper.py
+++ b/goblin/mapper.py
@@ -25,13 +25,37 @@ from goblin import exception
 logger = logging.getLogger(__name__)
 
 
+# def map_props_to_db(element, mapping):
+#     """Convert OGM property names/values to DB property names/values"""
+#     property_tuples = []
+#     props = mapping.ogm_properties
+#     for ogm_name, (db_name, data_type) in props.items():
+#         val = getattr(element, ogm_name, None)
+#         property_tuples.append((db_name, data_type.to_db(val)))
+#     return property_tuples
+
+
+#######IMPLEMENT
 def map_props_to_db(element, mapping):
     """Convert OGM property names/values to DB property names/values"""
     property_tuples = []
-    props = mapping.properties
+    props = mapping.ogm_properties
     for ogm_name, (db_name, data_type) in props.items():
         val = getattr(element, ogm_name, None)
-        property_tuples.append((db_name, data_type.to_db(val)))
+        # if val is list etc... these have card pass to next function maybe can give
+        # default option for Card, and combin this function with map props, and then add_properties
+        if val and isinstance(val, (list, set)):
+            card = None
+            for v in val:
+                # get metaprops as dic
+                metaprops = {}
+                property_tuples.append(
+                    (card, db_name, data_type.to_db(v.value), metaprops))
+                card = v.cardinality
+        else:
+            if hasattr(val, '__mapping__'):
+                val = val.value
+            property_tuples.append((None, db_name, data_type.to_db(val), None))
     return property_tuples
 
 
@@ -39,8 +63,12 @@ def map_vertex_to_ogm(result, element, *, mapping=None):
     """Map a vertex returned by DB to OGM vertex"""
     for db_name, value in result['properties'].items():
         # This will be more complex for vertex properties...
-        value = value[0]['value']
-        name, data_type = mapping.properties.get(db_name, (db_name, None))
+        if len(value) > 1:
+            # parse and assign vertex props + metas
+            value = [v['value'] for v in value]
+        else:
+            value = value[0]['value']
+        name, data_type = mapping.db_properties.get(db_name, (db_name, None))
         if data_type:
             value = data_type.to_ogm(value)
         setattr(element, name, value)
@@ -52,7 +80,7 @@ def map_vertex_to_ogm(result, element, *, mapping=None):
 def map_edge_to_ogm(result, element, *, mapping=None):
     """Map an edge returned by DB to OGM edge"""
     for db_name, value in result.get('properties', {}).items():
-        name, data_type = mapping.properties.get(db_name, (db_name, None))
+        name, data_type = mapping.db_properties.get(db_name, (db_name, None))
         if data_type:
             value = data_type.to_ogm(value)
         setattr(element, name, value)
@@ -104,19 +132,16 @@ class Mapping:
         self._label = namespace['__label__']
         self._element_type = element_type
         self._mapper_func = functools.partial(mapper_func, mapping=self)
-        self._properties = {}
-        if self._element_type == 'vertex':
-            self._vertex_properties = {}
-        else:
-            self._vertex_properties = None
+        self._db_properties = {}
+        self._ogm_properties = {}
         self._map_properties(properties)
 
-    @property
-    def vertex_properties(self):
-        if self._vertex_properties is None:
-            raise exception.MappingError(
-                'Edge mappings do not have vertex_properties')
-        return self._vertex_properties
+    # @property
+    # def vertex_properties(self):
+    #     if self._vertex_properties is None:
+    #         raise exception.MappingError(
+    #             'Edge mappings do not have vertex_properties')
+    #     return self._vertex_properties
 
     @property
     def label(self):
@@ -129,13 +154,18 @@ class Mapping:
         return self._mapper_func
 
     @property
-    def properties(self):
+    def db_properties(self):
+        """A dictionary of property mappings"""
+        return self._db_properties
+
+    @property
+    def ogm_properties(self):
         """A dictionary of property mappings"""
-        return self._properties
+        return self._ogm_properties
 
     def __getattr__(self, value):
         try:
-            mapping, _ = self._properties[value]
+            mapping, _ = self._ogm_properties[value]
             return mapping
         except:
             raise exception.MappingError(
@@ -144,20 +174,22 @@ class Mapping:
 
     def _map_properties(self, properties):
         for name, prop in properties.items():
-            if hasattr(prop, '__mapping__'):
-                if not self._element_type == 'vertex':
-                    raise exception.MappingError(
-                        'Only vertices can have vertex properties')
-                self._vertex_properties[name] = prop
             data_type = prop.data_type
             if prop.db_name:
                 db_name = prop.db_name
             else:
                 db_name = '{}__{}'.format(self._label, name)
-            self._properties[db_name] = (name, data_type)
-            self._properties[name] = (db_name, data_type)
+            if hasattr(prop, '__mapping__'):
+                if not self._element_type == 'vertex':
+                    raise exception.MappingError(
+                        'Only vertices can have vertex properties')
+                # self._vertex_properties[db_name] = (name, data_type)
+                # self._vertex_properties[name] = (db_name, data_type)
+            # else:
+            self._db_properties[db_name] = (name, data_type)
+            self._ogm_properties[name] = (db_name, data_type)
 
     def __repr__(self):
         return '<{}(type={}, label={}, properties={})>'.format(
             self.__class__.__name__, self._element_type, self._label,
-            self._properties)
+            self._ogm_properties)
diff --git a/goblin/properties.py b/goblin/properties.py
index 344446d5989c22e0267885c4f5026a2c3b945665..91b7572094544447044597524bf98f2b61fa879f 100644
--- a/goblin/properties.py
+++ b/goblin/properties.py
@@ -19,7 +19,7 @@
 
 import logging
 
-from goblin import abc, exception
+from goblin import abc, cardinality, exception
 
 
 logger = logging.getLogger(__name__)
@@ -36,7 +36,6 @@ class PropertyDescriptor:
         self._name = '_' + name
         self._data_type = prop.data_type
         self._default = prop.default
-        self._cardinality = prop.cardinality
 
     def __get__(self, obj, objtype):
         if obj is None:
@@ -44,7 +43,7 @@ class PropertyDescriptor:
         return getattr(obj, self._name, self._default)
 
     def __set__(self, obj, val):
-        val = self._data_type.validate_cardinality(val, self._cardinality)
+        val = self._data_type.validate(val)
         setattr(obj, self._name, val)
 
     def __delete__(self, obj):
@@ -66,13 +65,9 @@ class Property(abc.BaseProperty):
 
     __descriptor__ = PropertyDescriptor
 
-    def __init__(self, data_type, *, cardinality=None, db_name=None,
-                 default=None):
+    def __init__(self, data_type, *, db_name=None, default=None):
         if isinstance(data_type, type):
             data_type = data_type()
-        if cardinality is not None:
-            cardinality = cardinality()
-        self._cardinality = cardinality
         self._data_type = data_type
         self._db_name = db_name
         self._default = default
@@ -89,10 +84,6 @@ class Property(abc.BaseProperty):
     def default(self):
         return self._default
 
-    @property
-    def cardinality(self):
-        return self._cardinality
-
 
 # Data types
 class String(abc.DataType):
@@ -120,7 +111,7 @@ class Integer(abc.DataType):
         if val is not None:
             try:
                 return int(val)
-            except ValueError as e:
+            except (ValueError, TypeError) as e:
                 raise exception.ValidationError(
                     'Not a valid integer: {}'.format(val)) from e
 
diff --git a/goblin/session.py b/goblin/session.py
index 4a3c832a6c7a9f920c1368949e9aa516f4d7d8cd..6ed6f673a5a93d76b24942cb3f2445ad7194a3c1 100644
--- a/goblin/session.py
+++ b/goblin/session.py
@@ -276,6 +276,7 @@ class Session(connection.AbstractConnection):
         :returns: :py:class:`Vertex<goblin.element.Vertex>` object
         """
         props = mapper.map_props_to_db(vertex, vertex.__mapping__)
+        # vert_props = mapper.map_vert_props_to_db
         traversal = self.g.V(vertex.id)
         return await self._update_vertex_properties(vertex, traversal, props)
 
@@ -346,14 +347,15 @@ class Session(connection.AbstractConnection):
         return await stream.fetch_data()
 
     async def _update_vertex_properties(self, element, traversal, props):
-        traversal, removals = self.traversal_factory.add_vertex_properties(
+        traversal, removals = self.traversal_factory.add_properties(
             traversal, props)
+        # traversal, removals = self.traversal_factory.add_vertex_properties(...)
         for k in removals:
             await self.g.V(element.id).properties(k).drop().one_or_none()
         return traversal
 
     async def _update_edge_properties(self, element, traversal, props):
-        traversal, removals = self.traversal_factory.add_edge_properties(
+        traversal, removals = self.traversal_factory.add_properties(
             traversal, props)
         for k in removals:
             await self.g.E(element.id).properties(k).drop().one_or_none()
diff --git a/goblin/traversal.py b/goblin/traversal.py
index 895295047552fea8168f202b1f49f9ba7781e952..0a2b3acd63dacc5c26636eea70d8ee0c0d696761 100644
--- a/goblin/traversal.py
+++ b/goblin/traversal.py
@@ -21,7 +21,7 @@ import asyncio
 import functools
 import logging
 
-from goblin import element, mapper
+from goblin import cardinality, element, mapper
 from goblin.driver import connection, graph
 from gremlin_python import process
 
@@ -42,7 +42,7 @@ def bindprop(element_class, ogm_name, val, *, binding=None):
     :returns: tuple object ('db_property_name', ('binding(if passed)', val))
     """
     db_name = getattr(element_class, ogm_name, ogm_name)
-    _, data_type = element_class.__mapping__.properties[ogm_name]
+    _, data_type = element_class.__mapping__.ogm_properties[ogm_name]
     val = data_type.to_db(val)
     if binding:
         val = (binding, val)
@@ -142,8 +142,10 @@ class TraversalFactory:
     def add_vertex(self, elem):
         """Convenience function for generating crud traversals."""
         props = mapper.map_props_to_db(elem, elem.__mapping__)
+        # vert_props = mapper.map_props_to_db
         traversal = self.traversal().addV(elem.__mapping__.label)
-        traversal, _ = self.add_vertex_properties(traversal, props)
+        traversal, _ = self.add_properties(traversal, props)
+        # traversal, _ = self.add_vertex_properties(...)
         return traversal
 
     def add_edge(self, elem):
@@ -153,49 +155,58 @@ class TraversalFactory:
         traversal = traversal.addE(elem.__mapping__._label)
         traversal = traversal.to(
             self.traversal().V(elem.target.id))
-        traversal, _ = self.add_edge_properties(traversal, props)
+        traversal, _ = self.add_properties(traversal, props)
         return traversal
 
-    def add_vertex_properties(self, traversal, props):
+    # def add_vertex_properties(self, traversal, props):
+    #     # refactor
+    #     binding = 0
+    #     potential_removals = []
+    #     for k, v in props:
+    #         if v:
+    #             if isinstance(v, element.VertexProperty):
+    #                 v = v.value
+    #             if isinstance(v, (list, set)):
+    #                 new_val = []
+    #                 for val in v:
+    #                     if isinstance(val, element.VertexProperty):
+    #                         val = val.value
+    #                     new_val.append(val)
+    #                 if isinstance(v, set):
+    #                     cardinality = process.Cardinality.set
+    #                 else:
+    #                     cardinality = process.Cardinality.list
+    #                 traversal = traversal.property(
+    #                     cardinality,
+    #                     ('k' + str(binding), k),
+    #                     ('v' + str(binding), new_val))
+    #             else:
+    #                 traversal = traversal.property(
+    #                     ('k' + str(binding), k),
+    #                     ('v' + str(binding), v))
+    #             binding += 1
+    #         else:
+    #             potential_removals.append(k)
+    #     return traversal, potential_removals
+
+    def add_properties(self, traversal, props):
         binding = 0
         potential_removals = []
-        for k, v in props:
-            if v:
-                if isinstance(v, element.VertexProperty):
-                    v = v.value
-                if isinstance(v, (list, set)):
-                    new_val = []
-                    for val in v:
-                        if isinstance(val, element.VertexProperty):
-                            val = val.value
-                        new_val.append(val)
-                    if isinstance(v, set):
-                        new_val = set(new_val)
-                        cardinality = Cardinality.set
+        for card, db_name, val, metaprops in props:
+            if val:
+                key = ('k' + str(binding), db_name)
+                val = ('v' + str(binding), val)
+                if card:
+                    if card == cardinality.Cardinality.list:
+                        card = process.Cardinality.list
+                    elif card == cardinality.Cardinality.set:
+                        card = process.Cardinality.set
                     else:
-                        cardinality = Cardinality.list
-                    traversal = traversal.property(
-                        cardinality,
-                        ('k' + str(binding), k),
-                        ('*v' + str(binding), new_val))
+                        card = process.Cardinality.single
+                    traversal = traversal.property(card, key, val)
                 else:
-                    traversal = traversal.property(
-                        ('k' + str(binding), k),
-                        ('v' + str(binding), v))
+                    traversal = traversal.property(key, val)
                 binding += 1
             else:
-                potential_removals.append(k)
-        return traversal, potential_removals
-
-    def add_edge_properties(self, traversal, props):
-        binding = 0
-        potential_removals = []
-        for k, v in props:
-            if v:
-                traversal = traversal.property(
-                    ('k' + str(binding), k),
-                    ('v' + str(binding), v))
-                binding += 1
-            else:
-                potential_removals.append(k)
+                potential_removals.append(db_name)
         return traversal, potential_removals
diff --git a/tests/conftest.py b/tests/conftest.py
index fc516c5dee3d6bacf05627dde126ab4bf3b38bdd..0040676cd7751f3f803265a2d73c1b450704d33c 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -16,24 +16,29 @@
 # along with Goblin.  If not, see <http://www.gnu.org/licenses/>.
 
 import pytest
-from goblin import create_app, driver, element, properties
+from goblin import create_app, driver, element, properties, Cardinality
 from gremlin_python import process
 
 
-class PlaceName(element.VertexProperty):
-    pass
+# class PlaceName(element.VertexProperty):
+#     pass
 
 
 class Person(element.Vertex):
     __label__ = 'person'
-    name = properties.Property(properties.String, cardinality=list)
+    name = properties.Property(properties.String)
     age = properties.Property(properties.Integer,
                               db_name='custom__person__age')
+    birthplace = element.VertexProperty(properties.String)
+    nicknames = element.VertexProperty(
+        properties.String, card=Cardinality.list)
 
 
 class Place(element.Vertex):
-    name = PlaceName(properties.String, cardinality=set)
+    name = properties.Property(properties.String)
     zipcode = properties.Property(properties.Integer)
+    important_numbers = element.VertexProperty(
+        properties.Integer, card=Cardinality.set)
 
 
 class Knows(element.Edge):
diff --git a/tests/test_mapper.py b/tests/test_mapper.py
index 592f90060def47334daacebbfe77e906db1b6ba9..ffb86627f500ea2a34b4c75b9f94f44fe1f5a8b0 100644
--- a/tests/test_mapper.py
+++ b/tests/test_mapper.py
@@ -21,16 +21,26 @@ from goblin import exception, properties
 
 
 def test_property_mapping(person, lives_in):
-    db_name, data_type = person.__mapping__._properties['name']
+    db_name, data_type = person.__mapping__._ogm_properties['name']
     assert  db_name == 'person__name'
     assert isinstance(data_type, properties.String)
-    db_name, data_type = person.__mapping__._properties['age']
+    db_name, data_type = person.__mapping__._ogm_properties['age']
     assert  db_name == 'custom__person__age'
     assert isinstance(data_type, properties.Integer)
-    db_name, data_type = lives_in.__mapping__._properties['notes']
+    db_name, data_type = lives_in.__mapping__._ogm_properties['notes']
     assert  db_name == 'lives_in__notes'
     assert isinstance(data_type, properties.String)
 
+    ogm_name, data_type = person.__mapping__._db_properties['person__name']
+    assert  ogm_name == 'name'
+    assert isinstance(data_type, properties.String)
+    ogm_name, data_type = person.__mapping__._db_properties['custom__person__age']
+    assert  ogm_name == 'age'
+    assert isinstance(data_type, properties.Integer)
+    ogm_name, data_type = lives_in.__mapping__._db_properties['lives_in__notes']
+    assert  ogm_name == 'notes'
+    assert isinstance(data_type, properties.String)
+
 
 def test_label_creation(place, lives_in):
     assert place.__mapping__._label == 'place'
diff --git a/tests/test_properties.py b/tests/test_properties.py
index bcba03b917c1eba7c5631a81cdc5e56b4c659322..80997e97447d44c8d6ddbbb061c265cb9e3896cc 100644
--- a/tests/test_properties.py
+++ b/tests/test_properties.py
@@ -17,6 +17,8 @@
 
 import pytest
 
+from goblin import element, exception, manager, properties
+
 
 def test_set_change_property(person, lives_in):
     # vertex
@@ -52,6 +54,86 @@ def test_setattr_validation(person):
         setattr(person, 'age', 'hello')
 
 
+# Vertex properties
+def test_set_change_vertex_property(person):
+    assert not person.birthplace
+    person.birthplace = 'Iowa City'
+    assert isinstance(person.birthplace, element.VertexProperty)
+    assert person.birthplace.value == 'Iowa City'
+    person.birthplace = 'U of I Hospital'
+    assert person.birthplace.value == 'U of I Hospital'
+
+
+def test_validate_vertex_prop(person):
+    assert not person.birthplace
+    person.birthplace = 1
+    assert person.birthplace.value == '1'
+
+
+def test_set_change_list_card_vertex_property(person):
+    assert not person.nicknames
+    person.nicknames = 'sly'
+    assert isinstance(person.nicknames, list)
+    assert isinstance(person.nicknames, manager.ListVertexPropertyManager)
+    assert isinstance(person.nicknames[0], element.VertexProperty)
+    assert person.nicknames[0].value == 'sly'
+    assert person.nicknames('sly') == person.nicknames[0]
+    person.nicknames = set(['sly', 'guy'])
+    assert isinstance(person.nicknames, list)
+    assert person.nicknames('sly').value == 'sly'
+    assert person.nicknames('guy').value == 'guy'
+    person.nicknames = ('sly', 'big', 'guy')
+    assert isinstance(person.nicknames, list)
+    assert [v.value for v in person.nicknames] == ['sly', 'big', 'guy']
+    person.nicknames = ['sly', 'big', 'guy', 'guy']
+    assert isinstance(person.nicknames, list)
+    assert len(person.nicknames('guy')) == 2
+    assert [v.value for v in person.nicknames] == ['sly', 'big', 'guy', 'guy']
+    person.nicknames.append(1)
+    assert person.nicknames('1').value == '1'
+
+
+def test_list_card_vertex_property_validation(person):
+    person.nicknames = [1, 1.5, 2]
+    assert [v.value for v in person.nicknames] == ['1', '1.5', '2']
+
+
+def test_set_change_set_card_vertex_property(place):
+    assert not place.important_numbers
+    place.important_numbers = 1
+    assert isinstance(place.important_numbers, set)
+    assert isinstance(
+        place.important_numbers, manager.SetVertexPropertyManager)
+    number_one, = place.important_numbers
+    assert isinstance(number_one, element.VertexProperty)
+    assert number_one.value == 1
+    assert place.important_numbers(1) == number_one
+    place.important_numbers = [1, 2]
+    assert isinstance(place.important_numbers, set)
+    assert {v.value for v in place.important_numbers} == set([1, 2])
+    place.important_numbers.add(3)
+    assert {v.value for v in place.important_numbers} == set([1, 2, 3])
+    place.important_numbers = (1, 2, 3, 4)
+    assert isinstance(place.important_numbers, set)
+    assert {v.value for v in place.important_numbers} == set([1, 2, 3, 4])
+    place.important_numbers = set([1, 2, 3])
+    assert isinstance(place.important_numbers, set)
+    assert {v.value for v in place.important_numbers} == set([1, 2, 3])
+    with pytest.raises(exception.ValidationError):
+        place.important_numbers.add('dude')
+
+
+def test_set_card_validation_vertex_property(place):
+    with pytest.raises(exception.ValidationError):
+        place.important_numbers = set(['hello', 2, 3])
+
+
+def test_cant_set_vertex_prop_on_edge():
+    with pytest.raises(exception.MappingError):
+        class MyEdge(element.Edge):
+            vert_prop = element.VertexProperty(properties.String)
+
+
 class TestString:
 
     def test_validation(self, string):
diff --git a/tests/test_session.py b/tests/test_session.py
index 1e89acc355f7c38d6009bb71a421eaf0e620df71..d60d3cd6ec530946ba84942e8ebf321a665c32b5 100644
--- a/tests/test_session.py
+++ b/tests/test_session.py
@@ -15,6 +15,8 @@
 # You should have received a copy of the GNU Affero General Public License
 # along with Goblin.  If not, see <http://www.gnu.org/licenses/>.
 
+"""Functional sessions tests"""
+
 import pytest
 
 from goblin import element
@@ -44,7 +46,7 @@ class TestCreationApi:
             jon.name = 'jonathan'
             jon.age = 38
             leif = person_class()
-            leif.name = 'leif'
+            leif.name = 'leifur'
             leif.age = 28
             session.add(jon, leif)
             assert not hasattr(jon, 'id')
@@ -53,9 +55,11 @@ class TestCreationApi:
             assert hasattr(jon, 'id')
             assert session.current[jon.id] is jon
             assert jon.name == 'jonathan'
+            assert jon.age == 38
             assert hasattr(leif, 'id')
             assert session.current[leif.id] is leif
-            assert leif.name == 'leif'
+            assert leif.name == 'leifur'
+            assert leif.age == 28
 
     @pytest.mark.asyncio
     async def test_create_edge(self, session, person_class, place_class,
@@ -182,6 +186,7 @@ class TestCreationApi:
             person.name = 'dave'
             person.age = 35
             result = await session.save(person)
+            assert result.name == 'dave'
             assert result.age == 35
             person.name = 'david'
             person.age = None
@@ -267,10 +272,10 @@ class TestTraversalApi:
     async def test_vertex_deserialization(self, session, person_class):
         async with session:
             resp = await session.g.addV('person').property(
-                person_class.name, 'leif').property('birthplace', 'detroit').one_or_none()
+                person_class.name, 'leif').property('place_of_birth', 'detroit').one_or_none()
             assert isinstance(resp, person_class)
             assert resp.name == 'leif'
-            assert resp.birthplace == 'detroit'
+            assert resp.place_of_birth == 'detroit'
 
     @pytest.mark.asyncio
     async def test_edge_desialization(self, session, knows_class):
diff --git a/tests/test_vertex_properties_functional.py b/tests/test_vertex_properties_functional.py
new file mode 100644
index 0000000000000000000000000000000000000000..96802f05c498f0f5c0abd380b511b91af8443f7f
--- /dev/null
+++ b/tests/test_vertex_properties_functional.py
@@ -0,0 +1,56 @@
+import pytest
+
+
+@pytest.mark.asyncio
+async def test_add_update_property(session, person):
+    async with session:
+        person.birthplace = 'Iowa City'
+        result = await session.save(person)
+        assert result.birthplace.value == 'Iowa City'
+        person.birthplace = 'unknown'
+        result = await session.save(person)
+        assert result.birthplace.value == 'unknown'
+
+
+@pytest.mark.asyncio
+async def test_add_update_list_card_property(session, person):
+    async with session:
+        person.nicknames = ['db', 'dirtydb']
+        result = await session.save(person)
+        assert [v.value for v in result.nicknames] == ['db', 'dirtydb']
+        person.nicknames.append('davebshow')
+        result = await session.save(person)
+        assert [v.value for v in result.nicknames] == [
+            'db', 'dirtydb', 'davebshow']
+        person.nicknames = []
+        result = await session.save(person)
+        assert not result.nicknames
+        person.nicknames = ['none']
+        result = await session.save(person)
+        assert result.nicknames('none').value == 'none'
+        person.nicknames = None
+        result = await session.save(person)
+        assert not result.nicknames
+
+
+@pytest.mark.asyncio
+async def test_add_update_list_card_property(session, place):
+    async with session:
+        place.important_numbers = set([1, 2])
+        result = await session.save(place)
+        assert {v.value for v in result.important_numbers} == {1, 2}
+        place.important_numbers = set([3, 4])
+        result = await session.save(place)
+        assert {v.value for v in result.important_numbers} == {3, 4}
+        place.important_numbers.add(5)
+        result = await session.save(place)
+        assert {v.value for v in result.important_numbers} == {3, 4, 5}
+        place.important_numbers = set()
+        result = await session.save(place)
+        assert not result.important_numbers
+        place.important_numbers = set([1, 2])
+        result = await session.save(place)
+        assert place.important_numbers(1).value == 1
+        place.important_numbers = None
+        result = await session.save(place)
+        assert not result.important_numbers