diff --git a/configdb/client/cli.py b/configdb/client/cli.py
index d26e55be76217131861d1312e7d6a3df572db1f6..cb30dbc127f7a3816c08f3cacae1e4cebe268acf 100644
--- a/configdb/client/cli.py
+++ b/configdb/client/cli.py
@@ -29,14 +29,21 @@ def read_from_file(value):
     with open(value, 'r') as fd:
         return fd.read()
 
+class JsonPlain(object):
+    @staticmethod
+    def pprint(value):
+        """Pretty-print value as JSON."""
+        print json.dumps(value, sort_keys=True, indent=4)
 
-def pprint(value):
-    """Pretty-print value as JSON."""
-    print json.dumps(value, sort_keys=True, indent=4)
 
 
 class Action(object):
+    view = JsonPlain
 
+    @classmethod
+    def set_view(cls, viewclass):
+        cls.view = viewclass
+        
     def parse_field_value(self, field, value):
         type_map = {
             'string': str,
@@ -154,7 +161,19 @@ class GetAction(Action):
 
     def run(self, conn, entity, args):
         obj = conn.get(entity.name, args._name)
-        pprint(obj)
+        self.view.pprint(obj)
+
+class TimestampAction(Action):
+    """Get the timestamp of last update on an entity."""
+
+    name = 'timestamp'
+
+    def __init__(self, entity, parser):
+        pass
+
+    def run(self, conn, entity, args):
+        print conn.get_timestamp(entity.name)
+        
 
 
 class FindAction(Action):
@@ -184,7 +203,7 @@ class FindAction(Action):
 
     def run(self, conn, entity, args):
         objects = conn.find(entity.name, self._get_query(entity, args))
-        pprint(objects)
+        self.view.pprint(objects)
 
 
 class DeleteAction(Action):
@@ -204,19 +223,24 @@ class AuditAction(object):
 
     name = 'audit'
     descr = 'query audit logs'
-
+    view = JsonPlain
+    
     AUDIT_ATTRS = ('entity', 'object', 'user', 'op')
 
+    @classmethod
+    def set_view(cls, viewclass):
+        cls.view = viewclass
+    
     def __init__(self, parser):
         for attr in self.AUDIT_ATTRS:
             parser.add_argument('--' + attr)
-
+            
     def run(self, conn, entity, args):
         query = dict((x, getattr(args, x))
                      for x in self.AUDIT_ATTRS
                      if getattr(args, x))
         log.info('audit query: %s', query)
-        pprint(list(conn.get_audit(query)))
+        self.view.pprint(list(conn.get_audit(query)))
 
 class DumpAction(object):
     """Dumps all configdb data to a file"""
@@ -255,6 +279,7 @@ class Parser(object):
         UpdateAction,
         GetAction,
         FindAction,
+        TimestampAction
         )
 
     toplevel_actions = (
@@ -295,6 +320,8 @@ class Parser(object):
             help='use with --help for additional help',
             dest='_entity_name')
         for entity in self.schema.get_entities():
+            if entity.name in self.schema.sys_schema_tables:
+                continue
             subparser = subparsers.add_parser(entity.name,
                                               help=entity.description)
             self._init_subparser(entity, subparser)
diff --git a/configdb/client/connection.py b/configdb/client/connection.py
index aa99d4bd18aa75d3eb84203e1fd65c7cf62b0a47..281ca6b28bcf6c9f02acfa7aa2749e9c987f70a4 100644
--- a/configdb/client/connection.py
+++ b/configdb/client/connection.py
@@ -204,7 +204,7 @@ class Connection(object):
             data = data.to_net()
         return [self._from_net(entity_name, x)
                 for x in self._call(entity_name, 'find', data=data)]
-
+    
     def get(self, entity_name, object_name):
         """Fetch a single object.
 
@@ -251,3 +251,16 @@ class Connection(object):
         """
         return self._request(['audit'], query)
 
+    def get_timestamp(self, entity_name):
+        """Fetch the timestamp of last update to a entity.
+
+        Args:
+          entity_name: string, entity name
+
+        Returns:
+          A String representing the unix epoch of last update
+
+        Raises:
+          None
+        """
+        return self._call(entity_name, 'timestamp')
diff --git a/configdb/db/db_api.py b/configdb/db/db_api.py
index f65356fc3c900bc6318e45ab5c671c44993ef6cf..3522c5b72151de68ce615d13d58929883b9802d7 100644
--- a/configdb/db/db_api.py
+++ b/configdb/db/db_api.py
@@ -1,4 +1,7 @@
 import functools
+
+from time import time
+
 from configdb import exceptions
 from configdb.db import acl
 from configdb.db import query
@@ -14,6 +17,14 @@ def with_session(fn):
     return _with_session_wrapper
 
 
+def with_timestamp(fn):
+    @functools.wraps(fn)
+    def _with_timestamp_wrapper(self, session, entity_name, *args, **kwargs):
+        res = fn(self, session, entity_name, *args, **kwargs)
+        self.update_timestamp(session, entity_name)
+        return res
+    return _with_timestamp_wrapper
+
 def _field_validation(field, value):
     return field.validate(value)
 
@@ -102,7 +113,26 @@ class AdmDbApi(object):
             else:
                 setattr(obj, field_name, new_value)
 
+    def update_timestamp(self, session, entity_name):
+        if entity_name in self.schema.sys_schema_tables:
+            #Avoid updating timestamp for tables that are not part of the schema.
+            return True
+        
+        data = {'name': entity_name, 'ts': time() }
+        ts = self.schema.get_entity('__timestamp')
+        data = self._unpack(ts, data)
+
+        obj = self.db.get_by_name('__timestamp', entity_name, session)
+        if obj:
+            diffs = self._diff_object(ts, obj, data)
+            self._apply_diff(ts, obj, diffs, session)
+            session.add(obj)
+        else:
+            obj = self.db.create('__timestamp', data, session)
+        return True
+        
     @with_session
+    @with_timestamp
     def update(self, session, entity_name, object_name, data, auth_context):
         """Update an existing instance."""
         ent = self.schema.get_entity(entity_name)
@@ -125,6 +155,7 @@ class AdmDbApi(object):
         return True
 
     @with_session
+    @with_timestamp
     def delete(self, session, entity_name, object_name, auth_context):
         """Delete an instance."""
         ent = self.schema.get_entity(entity_name)
@@ -141,6 +172,7 @@ class AdmDbApi(object):
         return True
 
     @with_session
+    @with_timestamp
     def create(self, session, entity_name, data, auth_context):
         """Create a new instance."""
         ent = self.schema.get_entity(entity_name)
@@ -160,6 +192,8 @@ class AdmDbApi(object):
 
         return True
 
+    
+
     @with_session
     def get(self, session, entity_name, object_name, auth_context):
         """Return a specific instance."""
@@ -207,3 +241,21 @@ class AdmDbApi(object):
 
         self.schema.acl_check_entity(ent, auth_context, 'r', None)
         return self.db.get_audit(query, session)
+
+    @with_session
+    def get_timestamp(self, session, entity_name, auth_context):
+        """Get the timestamp of the last update on an entity.
+
+        """
+        ent = self.schema.get_entity(entity_name)
+        if not ent:
+            raise exceptions.NotFound(entity_name)
+
+        self.schema.acl_check_entity(ent, auth_context, 'r', None)
+
+        obj = self.db.get_by_name('__timestamp', entity_name, session)
+        if not obj:
+            raise exceptions.NotFound(entity_name)
+        return obj
+        
+                                  
diff --git a/configdb/db/schema.py b/configdb/db/schema.py
index fe6c097256f9c699e065153f95ffbc0fce31c39a..311d74576a306e27a62e52865a66fd6ffd2fd786 100644
--- a/configdb/db/schema.py
+++ b/configdb/db/schema.py
@@ -160,12 +160,13 @@ class Schema(object):
     A schema consists of multiple Entities, each having multiple
     Fields. The definition is loaded from JSON-encoded data.
     """
-
+    sys_schema_tables = [ '__timestamp']                         
     def __init__(self, json_data):
         self.entities = {}
         schema_data = json.loads(json_data)
+        self._add_timestamp()
         for tname, tdata in schema_data.iteritems():
-            if not ENTITY_NAME_PATTERN.match(tname):
+            if not ENTITY_NAME_PATTERN.match(tname) or tname in self.sys_schema_tables:
                 raise exceptions.SchemaError(
                     'invalid entity name "%s"' % tname)
             self.entities[tname] = Entity(tname, tdata)
@@ -173,6 +174,10 @@ class Schema(object):
         self.default_acl = acl.AclMixin()
         self.default_acl.set_acl(DEFAULT_ACL)
 
+    def _add_timestamp(self):
+        ts_schema = {'name': { 'type': 'string', 'size': 32}, 'ts': {'type': 'number', 'nullable': False } }
+        self.entities['__timestamp'] = Entity('__timestamp', ts_schema)
+
     def _relation_check(self):
         """Verify that all relations reference existing entities."""
         seen = set()
@@ -190,7 +195,7 @@ class Schema(object):
         return self.entities.get(name)
 
     def get_entities(self):
-        return self.entities.itervalues()
+        return self.entities.itervalues() 
 
     def acl_check_fields(self, entity, fields, auth_context, op, obj):
         """Authorize an operation on the fields of an instance."""
diff --git a/configdb/server/wsgiapp.py b/configdb/server/wsgiapp.py
index e6f818bc9a6df402e88b41995c48973e7d3d02d4..0301015e18fb810cf4568da2e8dc708958419cbc 100644
--- a/configdb/server/wsgiapp.py
+++ b/configdb/server/wsgiapp.py
@@ -156,6 +156,15 @@ def find(class_name):
 def delete(class_name, object_name):
     return g.api.delete(class_name, object_name, g.auth_ctx)
 
+@api_app.route('/timestamp/<class_name>')
+@authenticate
+@json_response
+def ts(class_name):
+    try:
+        res = g.api.get_timestamp(class_name, g.auth_ctx)
+        return str(res.ts)
+    except exceptions.NotFound:
+        return "0"
 
 @api_app.route('/audit', methods=['POST'])
 @authenticate
diff --git a/configdb/tests/db_api_test_base.py b/configdb/tests/db_api_test_base.py
index 72e17121e05d295c73e521d8b098e38e1c6bf0ba..d06a4bfe135a1d0eb3594f5b5c11c547e009ceae 100644
--- a/configdb/tests/db_api_test_base.py
+++ b/configdb/tests/db_api_test_base.py
@@ -204,7 +204,7 @@ class DbApiTestBase(object):
     #                       self.api.get('host', 'utz', self.ctx).name)
     #     self.assertRaises(exceptions.NotFound,
     #                       self.api.get, 'host', 'obz', self.ctx)
-
+        
     def test_update_modify_relation(self):
         self.assertTrue(
             self.api.update('host', 'obz', {'roles': ['role2']}, self.ctx))
@@ -347,3 +347,16 @@ class DbApiTestBase(object):
                           self.api.get_audit,
                           {'entity': 'private', 'op': 'create'},
                           auth_ctx)
+
+    def test_timestamp_is_updated(self):
+        result = self.api.update('host', 'obz', {'ip': '2.3.4.5'}, self.ctx)
+        self.assertTrue(result)
+        ts1 = self.api.get_timestamp('host', self.ctx).ts
+        self.assertTrue(ts1 != 0)
+        result = self.api.update('host', 'obz', {'ip': '3.3.3.5'}, self.ctx)
+        self.assertTrue(result)
+        ts2 = self.api.get_timestamp('host', self.ctx).ts
+        self.assertTrue(ts2 > ts1)
+
+    def test_timestamp_for_non_updated_entity(self):
+        self.assertRaises(ValueError, self.api.get_timestamp('role',self.ctx))
diff --git a/configdb/tests/test_schema.py b/configdb/tests/test_schema.py
index 780fd33de4276af5757d548165277674dd027bb1..193ce212f830de07bb6d13bdc8d6928786d3062d 100644
--- a/configdb/tests/test_schema.py
+++ b/configdb/tests/test_schema.py
@@ -8,7 +8,7 @@ class SchemaTest(TestBase):
 
     def test_empty_schema_ok(self):
         s = schema.Schema('{}')
-        self.assertEquals({}, s.entities)
+        self.assertEquals(s.sys_schema_tables, s.entities.keys())
 
     def test_entity_without_name(self):
         data = """