diff --git a/cms/djangoapps/contentstore/utils.py b/cms/djangoapps/contentstore/utils.py
index d6dcc3811da445b96f256486d0a7a6232072214d..cb42c5a1fc435580aa561d103264cae60f0e45ad 100644
--- a/cms/djangoapps/contentstore/utils.py
+++ b/cms/djangoapps/contentstore/utils.py
@@ -122,7 +122,7 @@ def compute_unit_state(unit):
     'private' content is editabled and not visible in the LMS
     """
 
-    if unit.metadata.get('is_draft', False):
+    if unit.cms.is_draft:
         try:
             modulestore('direct').get_item(unit.location)
             return UnitState.draft
@@ -142,4 +142,4 @@ def update_item(location, value):
     if value is None:
         get_modulestore(location).delete_item(location)
     else:
-        get_modulestore(location).update_item(location, value)
\ No newline at end of file
+        get_modulestore(location).update_item(location, value)
diff --git a/cms/djangoapps/contentstore/views.py b/cms/djangoapps/contentstore/views.py
index 809e43dea305ee3500c2c0fcfa1ca0bf62182b7a..a6957e61070f4727d1ce0816ccdb6066f8cf72b0 100644
--- a/cms/djangoapps/contentstore/views.py
+++ b/cms/djangoapps/contentstore/views.py
@@ -29,11 +29,14 @@ from django.conf import settings
 from xmodule.modulestore import Location
 from xmodule.modulestore.exceptions import ItemNotFoundError, InvalidLocationError
 from xmodule.modulestore.inheritance import own_metadata
+from xmodule.model import Scope
+from xmodule.runtime import KeyValueStore, DbModel, InvalidScopeError
 from xmodule.x_module import ModuleSystem
 from xmodule.error_module import ErrorDescriptor
 from xmodule.errortracker import exc_info_to_str
 from static_replace import replace_urls
 from external_auth.views import ssl_login_shortcut
+from xmodule.modulestore.mongo import MongoUsage
 
 from mitxmako.shortcuts import render_to_response, render_to_string
 from xmodule.modulestore.django import modulestore
@@ -214,8 +217,13 @@ def edit_subsection(request, location):
 
     # remove all metadata from the generic dictionary that is presented in a more normalized UI
 
-    policy_metadata = dict((key,value) for key, value in item.metadata.iteritems() 
-        if key not in ['display_name', 'start', 'due', 'format'] and key not in item.system_metadata_fields)
+    policy_metadata = dict(
+        (key,value)
+        for field
+        in item.fields
+        if field.name not in ['display_name', 'start', 'due', 'format'] and
+           field.scope == Scope.settings
+    )
 
     can_view_live = False
     subsection_units = item.get_children()
@@ -312,11 +320,6 @@ def edit_unit(request, location):
 
     unit_state = compute_unit_state(item)
 
-    try:
-        published_date = time.strftime('%B %d, %Y', item.metadata.get('published_date'))
-    except TypeError:
-        published_date = None
-
     return render_to_response('unit.html', {
         'context_course': course,
         'active_tab': 'courseware',
@@ -327,11 +330,11 @@ def edit_unit(request, location):
         'draft_preview_link': preview_lms_link,
         'published_preview_link': lms_link,
         'subsection': containing_subsection,
-        'release_date': get_date_display(datetime.fromtimestamp(time.mktime(containing_subsection.start))) if containing_subsection.start is not None else None,
+        'release_date': get_date_display(datetime.fromtimestamp(time.mktime(containing_subsection.lms.start))) if containing_subsection.lms.start is not None else None,
         'section': containing_section,
         'create_new_unit_template': Location('i4x', 'edx', 'templates', 'vertical', 'Empty'),
         'unit_state': unit_state,
-        'published_date': published_date,
+        'published_date': item.cms.published_date.strftime('%B %d, %Y') if item.cms.published_date is not None else None,
     })
 
 
@@ -395,9 +398,8 @@ def preview_dispatch(request, preview_id, location, dispatch=None):
     dispatch: The action to execute
     """
 
-    instance_state, shared_state = load_preview_state(request, preview_id, location)
     descriptor = modulestore().get_item(location)
-    instance = load_preview_module(request, preview_id, descriptor, instance_state, shared_state)
+    instance = load_preview_module(request, preview_id, descriptor)
     # Let the module handle the AJAX
     try:
         ajax_return = instance.handle_ajax(dispatch, request.POST)
@@ -408,47 +410,40 @@ def preview_dispatch(request, preview_id, location, dispatch=None):
         log.exception("error processing ajax call")
         raise
 
-    save_preview_state(request, preview_id, location, instance.get_instance_state(), instance.get_shared_state())
+    print request.session.items()
+
     return HttpResponse(ajax_return)
 
 
-def load_preview_state(request, preview_id, location):
+def render_from_lms(template_name, dictionary, context=None, namespace='main'):
     """
-    Load the state of a preview module from the request
-
-    preview_id (str): An identifier specifying which preview this module is used for
-    location: The Location of the module to dispatch to
+    Render a template using the LMS MAKO_TEMPLATES
     """
-    if 'preview_states' not in request.session:
-        request.session['preview_states'] = defaultdict(dict)
-
-    instance_state = request.session['preview_states'][preview_id, location].get('instance')
-    shared_state = request.session['preview_states'][preview_id, location].get('shared')
-
-    return instance_state, shared_state
-
+    return render_to_string(template_name, dictionary, context, namespace="lms." + namespace)
 
-def save_preview_state(request, preview_id, location, instance_state, shared_state):
-    """
-    Save the state of a preview module to the request
 
-    preview_id (str): An identifier specifying which preview this module is used for
-    location: The Location of the module to dispatch to
-    instance_state: The instance state to save
-    shared_state: The shared state to save
-    """
-    if 'preview_states' not in request.session:
-        request.session['preview_states'] = defaultdict(dict)
+class SessionKeyValueStore(KeyValueStore):
+    def __init__(self, request, model_data):
+        self._model_data = model_data
+        self._session = request.session
 
-    request.session['preview_states'][preview_id, location]['instance'] = instance_state
-    request.session['preview_states'][preview_id, location]['shared'] = shared_state
+    def get(self, key):
+        try:
+            return self._model_data[key.field_name]
+        except (KeyError, InvalidScopeError):
+            return self._session[tuple(key)]
 
+    def set(self, key, value):
+        try:
+            self._model_data[key.field_name] = value
+        except (KeyError, InvalidScopeError):
+            self._session[tuple(key)] = value
 
-def render_from_lms(template_name, dictionary, context=None, namespace='main'):
-    """
-    Render a template using the LMS MAKO_TEMPLATES
-    """
-    return render_to_string(template_name, dictionary, context, namespace="lms." + namespace)
+    def delete(self, key):
+        try:
+            del self._model_data[key.field_name]
+        except (KeyError, InvalidScopeError):
+            del self._session[tuple(key)]
 
 
 def preview_module_system(request, preview_id, descriptor):
@@ -461,6 +456,14 @@ def preview_module_system(request, preview_id, descriptor):
     descriptor: An XModuleDescriptor
     """
 
+    def preview_model_data(model_data):
+        return DbModel(
+            SessionKeyValueStore(request, model_data),
+            descriptor.module_class,
+            preview_id,
+            MongoUsage(preview_id, descriptor.location.url()),
+        )
+
     return ModuleSystem(
         ajax_url=reverse('preview_dispatch', args=[preview_id, descriptor.location.url(), '']).rstrip('/'),
         # TODO (cpennington): Do we want to track how instructors are using the preview problems?
@@ -471,6 +474,7 @@ def preview_module_system(request, preview_id, descriptor):
         debug=True,
         replace_urls=replace_urls,
         user=request.user,
+        xmodule_model_data=preview_model_data,
     )
 
 
@@ -484,11 +488,10 @@ def get_preview_module(request, preview_id, location):
     location: A Location
     """
     descriptor = modulestore().get_item(location)
-    instance_state, shared_state = descriptor.get_sample_state()[0]
-    return load_preview_module(request, preview_id, descriptor, instance_state, shared_state)
+    return load_preview_module(request, preview_id, descriptor)
 
 
-def load_preview_module(request, preview_id, descriptor, instance_state, shared_state):
+def load_preview_module(request, preview_id, descriptor):
     """
     Return a preview XModule instantiated from the supplied descriptor, instance_state, and shared_state
 
@@ -502,10 +505,11 @@ def load_preview_module(request, preview_id, descriptor, instance_state, shared_
     try:
         module = descriptor.xmodule(system)
     except:
+        log.debug("Unable to load preview module", exc_info=True)
         module = ErrorDescriptor.from_descriptor(
             descriptor,
             error_msg=exc_info_to_str(sys.exc_info())
-        ).xmodule_constructor(system)(None, None)
+        ).xmodule(system)
 
     # cdodge: Special case 
     if module.location.category == 'static_tab':
@@ -523,11 +527,9 @@ def load_preview_module(request, preview_id, descriptor, instance_state, shared_
         
     module.get_html = replace_static_urls(
         module.get_html,
-        module.metadata.get('data_dir', module.location.course),
+        getattr(module, 'data_dir', module.location.course),
         course_namespace = Location([module.location.tag, module.location.org, module.location.course, None, None])
     )
-    save_preview_state(request, preview_id, descriptor.location.url(),
-        module.get_instance_state(), module.get_shared_state())
 
     return module
 
@@ -541,7 +543,7 @@ def get_module_previews(request, descriptor):
     """
     preview_html = []
     for idx, (instance_state, shared_state) in enumerate(descriptor.get_sample_state()):
-        module = load_preview_module(request, str(idx), descriptor, instance_state, shared_state)
+        module = load_preview_module(request, str(idx), descriptor)
         preview_html.append(module.get_html())
     return preview_html
 
@@ -625,23 +627,26 @@ def save_item(request):
 
         # update existing metadata with submitted metadata (which can be partial)
         # IMPORTANT NOTE: if the client passed pack 'null' (None) for a piece of metadata that means 'remove it'
-        for metadata_key in posted_metadata.keys():
+        for metadata_key, value in posted_metadata.items():
 
             # let's strip out any metadata fields from the postback which have been identified as system metadata
             # and therefore should not be user-editable, so we should accept them back from the client
             if metadata_key in existing_item.system_metadata_fields:
                 del posted_metadata[metadata_key]
             elif posted_metadata[metadata_key] is None:
+                print "DELETING", metadata_key, value
+                print metadata_key in existing_item._model_data
                 # remove both from passed in collection as well as the collection read in from the modulestore
-                if metadata_key in existing_item.metadata:
-                    del existing_item.metadata[metadata_key]
+                if metadata_key in existing_item._model_data:
+                    del existing_item._model_data[metadata_key]
                 del posted_metadata[metadata_key]
-
-        # overlay the new metadata over the modulestore sourced collection to support partial updates
-        existing_item.metadata.update(posted_metadata)
+            else:
+                existing_item._model_data[metadata_key] = value
 
         # commit to datastore
-        store.update_metadata(item_location, existing_item.metadata)
+        # TODO (cpennington): This really shouldn't have to do this much reaching in to get the metadata
+        print existing_item._model_data._kvs._metadata
+        store.update_metadata(item_location, existing_item._model_data._kvs._metadata)
 
     return HttpResponse()
 
diff --git a/cms/djangoapps/models/settings/course_grading.py b/cms/djangoapps/models/settings/course_grading.py
index 9ddbe87727bf5a7b1b5945a57c0183b948e08348..ce229dd196449f552d9230151726be3c9b7314bd 100644
--- a/cms/djangoapps/models/settings/course_grading.py
+++ b/cms/djangoapps/models/settings/course_grading.py
@@ -237,15 +237,15 @@ class CourseGradingModel:
         # 5 hours 59 minutes 59 seconds => converted to iso format
         rawgrace = descriptor.lms.graceperiod
         if rawgrace:
-            hours_from_day = rawgrace.days*24
+            hours_from_days = rawgrace.days*24
             seconds = rawgrace.seconds
             hours_from_seconds = int(seconds / 3600)
             seconds -= hours_from_seconds * 3600
             minutes = int(seconds / 60)
             seconds -= minutes * 60
             return {
-                'hours': hourse_from_days + hours_from_seconds,
-                'minutes': minutes_from_seconds,
+                'hours': hours_from_days + hours_from_seconds,
+                'minutes': minutes,
                 'seconds': seconds,
             }
         else:
diff --git a/cms/templates/edit_subsection.html b/cms/templates/edit_subsection.html
index 53567c73e192381b39738b48b6f25d8c9e083e4c..e98ad526ed562ea9ae5b48ae51ca540ff8b18b58 100644
--- a/cms/templates/edit_subsection.html
+++ b/cms/templates/edit_subsection.html
@@ -25,7 +25,7 @@
         </div>
         <div>
           <label>Format:</label>
-          <input type="text" value="${subsection.metadata['format'] if 'format' in subsection.metadata else ''}" class="unit-subtitle" data-metadata-name="format"/>
+          <input type="text" value="${subsection.lms.format}" class="unit-subtitle" data-metadata-name="format"/>
         </div>
         <div class="sortable-unit-list">
           <label>Units:</label>
@@ -54,13 +54,13 @@
         <label>Release date:<!-- <span class="description">Determines when this subsection and the units within it will be released publicly.</span>--></label>
         <div class="datepair" data-language="javascript">
             <%
-                start_date = datetime.fromtimestamp(mktime(subsection.start)) if subsection.start is not None else None
-                parent_start_date = datetime.fromtimestamp(mktime(parent_item.start)) if parent_item.start is not None else None
+                start_date = datetime.fromtimestamp(mktime(subsection.lms.start)) if subsection.lms.start is not None else None
+                parent_start_date = datetime.fromtimestamp(mktime(parent_item.lms.start)) if parent_item.lms.start is not None else None
             %>
           <input type="text" id="start_date" name="start_date" value="${start_date.strftime('%m/%d/%Y') if start_date is not None else ''}" placeholder="MM/DD/YYYY" class="date" size='15' autocomplete="off"/>
           <input type="text" id="start_time" name="start_time" value="${start_date.strftime('%H:%M') if start_date is not None else ''}" placeholder="HH:MM" class="time" size='10' autocomplete="off"/> 
         </div>
-        % if subsection.start != parent_item.start and subsection.start:
+        % if subsection.lms.start != parent_item.lms.start and subsection.lms.start:
             % if parent_start_date is None:
             <p class="notice">The date above differs from the release date of ${parent_item.lms.display_name}, which is unset.
             % else:
@@ -83,7 +83,7 @@
         <p class="date-description">
           <%
               # due date uses it own formatting for stringifying the date. As with capa_module.py, there's a utility module available for us to use
-             due_date = dateutil.parser.parse(subsection.metadata.get('due')) if 'due' in subsection.metadata else None
+             due_date = dateutil.parser.parse(subsection.lms.due) if subsection.lms.due is not None else None
           %>
           <input type="text" id="due_date" name="due_date" value="${due_date.strftime('%m/%d/%Y') if due_date is not None else ''}" placeholder="MM/DD/YYYY" class="date" size='15' autocomplete="off"/> 
           <input type="text" id="due_time" name="due_time" value="${due_date.strftime('%H:%M') if due_date is not None else ''}" placeholder="HH:MM" class="time" size='10' autocomplete="off"/>
diff --git a/cms/templates/overview.html b/cms/templates/overview.html
index fad28dbf07e1784a02f722e6f0b48a419a43a958..099cfb1a5bff985ee069fb59fbdb623cf5769dcb 100644
--- a/cms/templates/overview.html
+++ b/cms/templates/overview.html
@@ -141,7 +141,7 @@
               </h3>
               <div class="section-published-date">
                 <%
-                  start_date = datetime.fromtimestamp(mktime(section.start)) if section.start is not None else None
+                  start_date = datetime.fromtimestamp(mktime(section.lms.start)) if section.lms.start is not None else None
                   start_date_str = start_date.strftime('%m/%d/%Y') if start_date is not None else ''
                   start_time_str = start_date.strftime('%H:%M') if start_date is not None else ''
                 %>
@@ -178,7 +178,7 @@
                     </a>
                   </div>
                   
-                  <div class="gradable-status" data-initial-status="${subsection.metadata.get('format', 'Not Graded')}">
+                  <div class="gradable-status" data-initial-status="${subsection.lms.format if section.lms.format is not None else 'Not Graded'}">
                   </div>
                   
                   <div class="item-actions">
diff --git a/cms/xmodule_namespace.py b/cms/xmodule_namespace.py
new file mode 100644
index 0000000000000000000000000000000000000000..0ea729e27ba83b7f4ad5166f2644654fadafd192
--- /dev/null
+++ b/cms/xmodule_namespace.py
@@ -0,0 +1,20 @@
+import datetime
+
+from xmodule.model import Namespace, Boolean, Scope, ModelType, String
+
+
+class DateTuple(ModelType):
+    """
+    ModelType that stores datetime objects as time tuples
+    """
+    def from_json(self, value):
+        return datetime.datetime(*value)
+
+    def to_json(self, value):
+        return list(value.timetuple())
+
+
+class CmsNamespace(Namespace):
+    is_draft = Boolean(help="Whether this module is a draft", default=False, scope=Scope.settings)
+    published_date = DateTuple(help="Date when the module was published", scope=Scope.settings)
+    published_by = String(help="Id of the user who published this module", scope=Scope.settings)
diff --git a/common/lib/xmodule/xmodule/editing_module.py b/common/lib/xmodule/xmodule/editing_module.py
index e025179b63e2fc916a56a84b6dd44ed2670241bc..531fd7d8b9f1068a4ea73ffd1af3c7e32506f397 100644
--- a/common/lib/xmodule/xmodule/editing_module.py
+++ b/common/lib/xmodule/xmodule/editing_module.py
@@ -1,5 +1,6 @@
 from pkg_resources import resource_string
 from xmodule.mako_module import MakoModuleDescriptor
+from xmodule.model import Scope, String
 import logging
 
 log = logging.getLogger(__name__)
@@ -14,13 +15,15 @@ class EditingDescriptor(MakoModuleDescriptor):
     """
     mako_template = "widgets/raw-edit.html"
 
+    data = String(scope=Scope.content, default='')
+
     # cdodge: a little refactoring here, since we're basically doing the same thing
     # here as with our parent class, let's call into it to get the basic fields
     # set and then add our additional fields. Trying to keep it DRY.
     def get_context(self):
         _context = MakoModuleDescriptor.get_context(self)
         # Add our specific template information (the raw data body)
-        _context.update({'data': self.definition.get('data', '')})
+        _context.update({'data': self.data})
         return _context
 
 
diff --git a/common/lib/xmodule/xmodule/error_module.py b/common/lib/xmodule/xmodule/error_module.py
index 37e98b5b7797b05e89760c9310415ac499af8f16..6a06b3ad3afe27d08a30f2d718b87de11a3ce087 100644
--- a/common/lib/xmodule/xmodule/error_module.py
+++ b/common/lib/xmodule/xmodule/error_module.py
@@ -106,7 +106,7 @@ class ErrorDescriptor(JSONEditingDescriptor):
     def from_descriptor(cls, descriptor, error_msg='Error not available'):
         return cls._construct(
             descriptor.system,
-            json.dumps(descriptor._model_data, indent=4),
+            descriptor._model_data,
             error_msg,
             location=descriptor.location,
         )
diff --git a/common/lib/xmodule/xmodule/mako_module.py b/common/lib/xmodule/xmodule/mako_module.py
index bdf3cb474900d2e0fbebf106b5ddba7454d84dfa..8ae68051a0c5a68240b0feaa2973e5af08eae7ec 100644
--- a/common/lib/xmodule/xmodule/mako_module.py
+++ b/common/lib/xmodule/xmodule/mako_module.py
@@ -32,9 +32,7 @@ class MakoModuleDescriptor(XModuleDescriptor):
         """
         Return the context to render the mako template with
         """
-        return {'module': self,
-                'editable_metadata_fields': self.editable_fields
-                }
+        return {'module': self}
 
     def get_html(self):
         return self.system.render_template(
diff --git a/common/lib/xmodule/xmodule/modulestore/draft.py b/common/lib/xmodule/xmodule/modulestore/draft.py
index 5fbf05ed9bc738b0565ee3a0f58ef4159cc0f6b2..100bdb1dc6c605eb911a756a6b20a67db8c93183 100644
--- a/common/lib/xmodule/xmodule/modulestore/draft.py
+++ b/common/lib/xmodule/xmodule/modulestore/draft.py
@@ -15,11 +15,11 @@ def as_draft(location):
 
 def wrap_draft(item):
     """
-    Sets `item.metadata['is_draft']` to `True` if the item is a
-    draft, and false otherwise. Sets the item's location to the
+    Sets `item.cms.is_draft` to `True` if the item is a
+    draft, and `False` otherwise. Sets the item's location to the
     non-draft location in either case
     """
-    item.metadata['is_draft'] = item.location.revision == DRAFT
+    item.cms.is_draft = item.location.revision == DRAFT
     item.location = item.location._replace(revision=None)
     return item
 
@@ -112,7 +112,7 @@ class DraftModuleStore(ModuleStoreBase):
         """
         draft_loc = as_draft(location)
         draft_item = self.get_item(location)
-        if not draft_item.metadata['is_draft']:
+        if not draft_item.cms.is_draft:
             self.clone_item(location, draft_loc)
 
         return super(DraftModuleStore, self).update_item(draft_loc, data)
@@ -127,7 +127,7 @@ class DraftModuleStore(ModuleStoreBase):
         """
         draft_loc = as_draft(location)
         draft_item = self.get_item(location)
-        if not draft_item.metadata['is_draft']:
+        if not draft_item.cms.is_draft:
             self.clone_item(location, draft_loc)
 
         return super(DraftModuleStore, self).update_children(draft_loc, children)
@@ -143,7 +143,7 @@ class DraftModuleStore(ModuleStoreBase):
         draft_loc = as_draft(location)
         draft_item = self.get_item(location)
 
-        if not draft_item.metadata['is_draft']:
+        if not draft_item.cms.is_draft:
             self.clone_item(location, draft_loc)
 
         if 'is_draft' in metadata:
@@ -175,8 +175,8 @@ class DraftModuleStore(ModuleStoreBase):
         draft = self.get_item(location)
         metadata = {}
         metadata.update(draft.metadata)
-        metadata['published_date'] = tuple(datetime.utcnow().timetuple())
-        metadata['published_by'] = published_by_id
+        metadata.cms.published_date = datetime.utcnow()
+        metadata.cms.published_by = published_by_id
         super(DraftModuleStore, self).update_item(location, draft.definition.get('data', {}))
         super(DraftModuleStore, self).update_children(location, draft.definition.get('children', []))
         super(DraftModuleStore, self).update_metadata(location, metadata)
diff --git a/common/lib/xmodule/xmodule/modulestore/inheritance.py b/common/lib/xmodule/xmodule/modulestore/inheritance.py
index 38c592564d6c37cc640597343c88e66d8d169716..18cf0b33515a74925f5d9ac88ec3af82b5808b83 100644
--- a/common/lib/xmodule/xmodule/modulestore/inheritance.py
+++ b/common/lib/xmodule/xmodule/modulestore/inheritance.py
@@ -52,6 +52,11 @@ def own_metadata(module):
             field.name not in inherited_metadata and
             field.name in module._model_data):
 
-            metadata[field.name] = module._model_data[field.name]
+            try:
+                metadata[field.name] = module._model_data[field.name]
+            except KeyError:
+                # Ignore any missing keys in _model_data
+                pass
+
 
     return metadata
diff --git a/common/lib/xmodule/xmodule/modulestore/mongo.py b/common/lib/xmodule/xmodule/modulestore/mongo.py
index d145523d16cedd51120b941f7ce90345300e3d16..5c55c4d5076e11184bc4e739d4156fb5fb84912b 100644
--- a/common/lib/xmodule/xmodule/modulestore/mongo.py
+++ b/common/lib/xmodule/xmodule/modulestore/mongo.py
@@ -1,7 +1,9 @@
 import pymongo
 import sys
+import logging
 
 from bson.son import SON
+from collections import namedtuple
 from fs.osfs import OSFS
 from itertools import repeat
 from path import path
@@ -11,17 +13,79 @@ from xmodule.errortracker import null_error_tracker, exc_info_to_str
 from xmodule.mako_module import MakoDescriptorSystem
 from xmodule.x_module import XModuleDescriptor
 from xmodule.error_module import ErrorDescriptor
+from xmodule.runtime import DbModel, KeyValueStore, InvalidScopeError
+from xmodule.model import Scope
 
 from . import ModuleStoreBase, Location
 from .draft import DraftModuleStore
 from .exceptions import (ItemNotFoundError,
                          DuplicateItemError)
 
+
+log = logging.getLogger(__name__)
+
 # TODO (cpennington): This code currently operates under the assumption that
 # there is only one revision for each item. Once we start versioning inside the CMS,
 # that assumption will have to change
 
 
+class MongoKeyValueStore(KeyValueStore):
+    """
+    A KeyValueStore that maps keyed data access to one of the 3 data areas
+    known to the MongoModuleStore (data, children, and metadata)
+    """
+    def __init__(self, data, children, metadata):
+        self._data = data
+        self._children = children
+        self._metadata = metadata
+
+    def get(self, key):
+        print "GET", key
+        if key.field_name == 'children':
+            return self._children
+        elif key.scope == Scope.settings:
+            return self._metadata[key.field_name]
+        elif key.scope == Scope.content:
+            if key.field_name == 'data' and not isinstance(self._data, dict):
+                return self._data
+            else:
+                return self._data[key.field_name]
+        else:
+            raise InvalidScopeError(key.scope)
+
+    def set(self, key, value):
+        print "SET", key, value
+        if key.field_name == 'children':
+            self._children = value
+        elif key.scope == Scope.settings:
+            self._metadata[key.field_name] = value
+        elif key.scope == Scope.content:
+            if key.field_name == 'data' and not isinstance(self._data, dict):
+                self._data = value
+            else:
+                self._data[key.field_name] = value
+        else:
+            raise InvalidScopeError(key.scope)
+
+    def delete(self, key):
+        print "DELETE", key
+        if key.field_name == 'children':
+            self._children = []
+        elif key.scope == Scope.settings:
+            if key.field_name in self._metadata:
+                del self._metadata[key.field_name]
+        elif key.scope == Scope.content:
+            if key.field_name == 'data' and not isinstance(self._data, dict):
+                self._data = None
+            else:
+                del self._data[key.field_name]
+        else:
+            raise InvalidScopeError(key.scope)
+
+
+MongoUsage = namedtuple('MongoUsage', 'id, def_id')
+
+
 class CachingDescriptorSystem(MakoDescriptorSystem):
     """
     A system that has a cache of module json that it will use to load modules
@@ -64,8 +128,21 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
             # always load an entire course.  We're punting on this until after launch, and then
             # will build a proper course policy framework.
             try:
-                return XModuleDescriptor.load_from_json(json_data, self, self.default_class)
+                class_ = XModuleDescriptor.load_class(
+                    json_data['location']['category'],
+                    self.default_class
+                )
+                definition = json_data.get('definition', {})
+                kvs = MongoKeyValueStore(
+                    definition.get('data', {}),
+                    definition.get('children', []),
+                    json_data.get('metadata', {}),
+                )
+
+                model_data = DbModel(kvs, class_, None, MongoUsage(self.course_id, location))
+                return class_(self, location, model_data)
             except:
+                log.debug("Failed to load descriptor", exc_info=True)
                 return ErrorDescriptor.from_json(
                     json_data,
                     self,
diff --git a/common/lib/xmodule/xmodule/runtime.py b/common/lib/xmodule/xmodule/runtime.py
index 6dee5b0b008149296badc302186c4aaa5ed0d811..5a5533133b5ee977e7a278a09386c9fccfecf305 100644
--- a/common/lib/xmodule/xmodule/runtime.py
+++ b/common/lib/xmodule/xmodule/runtime.py
@@ -3,6 +3,13 @@ from collections import MutableMapping, namedtuple
 from .model import ModuleScope, ModelType
 
 
+class InvalidScopeError(Exception):
+    """
+    Raised to indicated that operating on the supplied scope isn't allowed by a KeyValueStore
+    """
+    pass
+
+
 class KeyValueStore(object):
     """The abstract interface for Key Value Stores."""
 
@@ -102,8 +109,12 @@ class DbModel(MutableMapping):
     def __len__(self):
         return len(self.keys())
 
+    def __contains__(self, item):
+        return item in self.keys()
+
     def keys(self):
         fields = [field.name for field in self._module_cls.fields]
         for namespace_name in self._module_cls.namespaces:
             fields.extend(field.name for field in getattr(self._module_cls, namespace_name).fields)
+        print fields
         return fields
diff --git a/common/lib/xmodule/xmodule/video_module.py b/common/lib/xmodule/xmodule/video_module.py
index ecc7d7fdad3dcb483447995faf9355183c5eaaaa..34ce353afdb07b32a6e744bd4499babe7ac3ef56 100644
--- a/common/lib/xmodule/xmodule/video_module.py
+++ b/common/lib/xmodule/xmodule/video_module.py
@@ -28,13 +28,41 @@ class VideoModule(XModule):
     css = {'scss': [resource_string(__name__, 'css/video/display.scss')]}
     js_module_name = "Video"
 
-    youtube = String(help="Youtube ids for each speed, in the format <speed>:<id>[,<speed>:<id> ...]", scope=Scope.content)
-    show_captions = String(help="Whether to display captions with this video", scope=Scope.content)
-    source = String(help="External source for this video", scope=Scope.content)
-    track = String(help="Subtitle file", scope=Scope.content)
-    position = Int(help="Current position in the video", scope=Scope.student_state, default=0)
+    data = String(help="XML data for the problem", scope=Scope.content)
+    position = Int(help="Current position in the video", scope=Scope.student_state)
     display_name = String(help="Display name for this module", scope=Scope.settings)
 
+    def __init__(self, *args, **kwargs):
+        XModule.__init__(self, *args, **kwargs)
+
+        xmltree = etree.fromstring(self.data)
+        self.youtube = xmltree.get('youtube')
+        self.position = 0
+        self.show_captions = xmltree.get('show_captions', 'true')
+        self.source = self._get_source(xmltree)
+        self.track = self._get_track(xmltree)
+
+    def _get_source(self, xmltree):
+        # find the first valid source
+        return self._get_first_external(xmltree, 'source')
+        
+    def _get_track(self, xmltree):
+        # find the first valid track
+        return self._get_first_external(xmltree, 'track')
+        
+    def _get_first_external(self, xmltree, tag):
+        """
+        Will return the first valid element
+        of the given tag.
+        'valid' means has a non-empty 'src' attribute
+        """
+        result = None
+        for element in xmltree.findall(tag):
+            src = element.get('src')
+            if src:
+                result = src
+                break
+        return result
 
     def handle_ajax(self, dispatch, get):
         '''
@@ -87,50 +115,7 @@ class VideoModule(XModule):
         })
 
 
-
 class VideoDescriptor(RawDescriptor):
     module_class = VideoModule
     stores_state = True
     template_dir_name = "video"
-
-    youtube = String(help="Youtube ids for each speed, in the format <speed>:<id>[,<speed>:<id> ...]", scope=Scope.content)
-    show_captions = String(help="Whether to display captions with this video", scope=Scope.content)
-    source = String(help="External source for this video", scope=Scope.content)
-    track = String(help="Subtitle file", scope=Scope.content)
-    
-    @classmethod
-    def definition_from_xml(cls, xml_object, system):
-        return {
-            'youtube': xml_object.get('youtube'),
-            'show_captions': xml_object.get('show_captions', 'true'),
-            'source': _get_first_external(xml_object, 'source'),
-            'track': _get_first_external(xml_object, 'track'),
-        }, []
-
-    def definition_to_xml(self, resource_fs):
-        xml_object = etree.Element('video', {
-            'youtube': self.youtube,
-            'show_captions': self.show_captions,
-        })
-
-        if self.source is not None:
-            SubElement(xml_object, 'source', {'src': self.source})
-
-        if self.track is not None:
-            SubElement(xml_object, 'track', {'src': self.track})
-
-        return xml_object
-    
-def _get_first_external(xmltree, tag):
-    """
-    Will return the first valid element
-    of the given tag.
-    'valid' means has a non-empty 'src' attribute
-    """
-    result = None
-    for element in xmltree.findall(tag):
-        src = element.get('src')
-        if src:
-            result = src
-            break
-    return result
diff --git a/lms/djangoapps/courseware/model_data.py b/lms/djangoapps/courseware/model_data.py
index e8dfb025edf29017a7b054018579e14996469130..b2f2d3ef4893f6541e2a82200c5a9b33769389ba 100644
--- a/lms/djangoapps/courseware/model_data.py
+++ b/lms/djangoapps/courseware/model_data.py
@@ -8,13 +8,10 @@ from .models import (
     XModuleStudentInfoField
 )
 
-from xmodule.runtime import DbModel, KeyValueStore
+from xmodule.runtime import KeyValueStore, InvalidScopeError
 from xmodule.model import Scope
 
 
-class InvalidScopeError(Exception):
-    pass
-
 class InvalidWriteError(Exception):
     pass
 
diff --git a/setup.py b/setup.py
index 84f242cf3dac3dab3d938ddad62ae75f3cdccfcd..a07f836413353a1ed5ce7e78b60352ec63de09f7 100644
--- a/setup.py
+++ b/setup.py
@@ -12,7 +12,8 @@ setup(
     # for a description of entry_points
     entry_points={
         'xmodule.namespace': [
-            'lms = lms.xmodule_namespace:LmsNamespace'
+            'lms = lms.xmodule_namespace:LmsNamespace',
+            'cms = cms.xmodule_namespace:CmsNamespace',
         ],
     }
 )
\ No newline at end of file