diff --git a/includes/cache.inc b/includes/cache.inc
index 8666874..861cd21 100644
--- a/includes/cache.inc
+++ b/includes/cache.inc
@@ -506,3 +506,137 @@ class DrupalDatabaseCache implements DrupalCacheInterface {
     return empty($result);
   }
 }
+
+/**
+ * Interface for allowing ArrayObject to be used as a caching wrapper.
+ *
+ * Extend CacheArrayObject rather than implementing this interface. This
+ * mainly exists to document/enforce methods for which there is no default
+ * implementation in CacheArrayObject.
+ */
+Interface CacheArrayObjectInterface {
+
+  /**
+   * Resolve a cache miss.
+   *
+   * When an offset is not found in the object, ensure it is populated. A
+   * a value of FALSE should be used to indicate that the item does not exist
+   * at all, and is not considered a valid value for ArrayObjects implementing
+   * this method.
+   *
+   * @param $offset
+   *   The offset that was requested.
+   */
+  public function resolveCacheMiss($offset);
+
+  /**
+   * Whether the array can be written to cache this request.
+   *
+   * @return
+   *  Boolean to indicate cacheability of the arrayObject.
+   */
+  public function cacheable();
+}
+
+
+/**
+ * Extends ArrayObject to enable it to be used as a caching wrapper.
+ *
+ * This class should be extended by systems that need to cache large amounts
+ * of data and have it represented as an array to calling functions. These
+ * arrays can become very large, so ArrayObject is used to allow different
+ * strategies to be used for caching internally (lazy loading, building caches
+ * over time etc.). This can dramatically reduce the amount of data that needs
+ * to be loaded from cache backends on each request, and memory usage from
+ * static caches of that same data.
+ *
+ * Note that array_key_exists() does not return the correct value on an
+ * arrayObject(),
+ *
+ * Additionally the methods provided here do not support the use of FALSE
+ * or NULL as values for array offsets. 0, '0', '' and array() or any other
+ * valid value for an array can be used without modification.
+ *
+ * Classes extending this must implement at least the __construct() and
+ * resolveCacheMiss() methods.
+ *
+ * @see ThemeRegistry
+ */
+class CacheArrayObject extends ArrayObject implements CacheArrayObjectInterface {
+
+  /**
+   * The unique cid to pass to cache_set().
+   */
+  private $cid;
+
+  /**
+   * The bin to cache the array in.
+   */
+  private $bin;
+
+  /**
+   * Whether there was a cache miss for an array offset during the request.
+   */
+  private $cache_miss;
+
+
+  /**
+   * Constructor.
+   *
+   * @param $cid
+   *   The cid for the array being cached.
+   * @param $bin
+   *   The bin to cache the array.a
+   */
+  function __construct($cid, $bin) {
+    $this->cid = $cid;
+    $this->bin = $bin;
+
+    if ($cached = cache_get($this->cid, $this->bin)) {
+      parent::__construct($cached->data);
+    }
+    else {
+      parent::__construct(array());
+    }
+  }
+
+  /**
+   * Check whether an array offset exists.
+   */
+  public function offsetExists($offset) {
+    if (!isset($this->$offset)) {
+      $this->resolveCacheMiss($offset);
+    }
+    return $this->$offset !== FALSE;
+  }
+
+  public function offsetGet($offset) {
+    if (!isset($this->$offset)) {
+      $this->resolveCacheMiss($offset);
+    }
+    return $this->$offset !== FALSE ? $this->$offset : NULL;
+  }
+
+  public function resolveCacheMiss($offset) {
+    // Setting the offset to FALSE causes offsetGet() and offsetSet()
+    // to act as if the item does not exist in the array. Most implementations
+    // will want to override this method to consult the structure being cached
+    // and set offset to the value if it exists there.
+    $this->$offset = FALSE;
+    $this->cache_miss = TRUE;
+  }
+
+  /**
+   * Whether the array can written to cache this request.
+   */
+  public function cacheable() {
+    return !empty($this->cache_miss);
+  }
+
+  public function __destruct() {
+    if ($this->cacheable()) {
+      cache_set($this->cid, $this->getarrayCopy(), $this->bin);
+    }
+  }
+}
+
diff --git a/includes/theme.inc b/includes/theme.inc
index c211248..3957afb 100644
--- a/includes/theme.inc
+++ b/includes/theme.inc
@@ -279,28 +279,7 @@ function _theme_registry_callback($callback = NULL, array $arguments = array())
  *   The name of the theme engine.
  */
 function _theme_load_registry($theme, $base_theme = NULL, $theme_engine = NULL) {
-  // Check the theme registry cache; if it exists, use it.
-  $cache = cache_get("theme_registry:$theme->name", 'cache');
-  if (isset($cache->data)) {
-    $registry = $cache->data;
-  }
-  else {
-    // If not, build one and cache it.
-    $registry = _theme_build_registry($theme, $base_theme, $theme_engine);
-   // Only persist this registry if all modules are loaded. This assures a
-   // complete set of theme hooks.
-    if (module_load_all(NULL)) {
-      _theme_save_registry($theme, $registry);
-    }
-  }
-  return $registry;
-}
-
-/**
- * Write the theme_registry cache into the database.
- */
-function _theme_save_registry($theme, $registry) {
-  cache_set("theme_registry:$theme->name", $registry);
+  return new ThemeRegistry($theme, $base_theme, $theme_engine);
 }
 
 /**
@@ -563,6 +542,57 @@ function _theme_build_registry($theme, $base_theme, $theme_engine) {
 }
 
 /**
+ * Builds the run-time theme registry.
+ *
+ * This class extends the CacheArrayObject class to allow the theme registry to be
+ * accessed as a complete registry, while internally caching only the parts of
+ * the registry that are actually in use on the site. On cache misses the
+ * complete theme registry is loade and used to update the run-time cache.
+ */
+class ThemeRegistry Extends CacheArrayObject {
+  private $theme;
+  private $base_theme;
+  private $theme_engine;
+
+  function __construct($theme, $base_theme = NULL, $theme_engine = NULL) {
+    // Make the arguments available to the rest of the class.
+    $this->theme = $theme;
+    $this->base_theme = $base_theme;
+    $this->theme_engine = $theme_engine;
+    $this->cid = 'theme_registry:' . $theme->name;
+    $this->bin = 'cache';
+
+    return parent::__construct($this->cid, $this->bin);
+  }
+
+  public function resolveCacheMiss($offset) {
+    $this->cache_miss = TRUE;
+    // Load the full theme registry.
+    if ($cached = cache_get('theme_registry:complete:' . $this->theme->name)) {
+      $complete_registry = $cached->data;
+    }
+    else {
+      $complete_registry = _theme_build_registry($this->theme, $this->base_theme, $this->theme_engine);
+      // Only persist this registry if all modules are loaded. This assures a
+      // complete set of theme hooks.
+      if (module_load_all(NULL)) {
+        cache_set('theme_registry:complete:' . $this->theme->name, $complete_registry);
+      }
+    }
+    if (isset($complete_registry[$offset])) {
+      $this->$offset = $complete_registry[$offset];
+    }
+    else {
+      $this->$offset = FALSE;
+    }
+  }
+
+  public function cacheable() {
+    return !empty($this->cache_miss) && module_load_all(NULL);
+  }
+}
+
+/**
  * Return a list of all currently available themes.
  *
  * Retrieved from the database, if available and the site is not in maintenance
