diff --git a/core/includes/module.inc b/core/includes/module.inc
index 1a52a80..76e8331 100644
--- a/core/includes/module.inc
+++ b/core/includes/module.inc
@@ -424,6 +424,8 @@ function module_enable($module_list, $enable_dependencies = TRUE) {
       registry_update();
       // Refresh the schema to include it.
       drupal_get_schema(NULL, TRUE);
+      // Update the theme registry to include it.
+      drupal_theme_rebuild();
 
       // Allow modules to react prior to the installation of a module.
       module_invoke_all('modules_preinstall', array($module));
@@ -543,6 +545,8 @@ function module_disable($module_list, $disable_dependents = TRUE) {
     // Update the registry to remove the newly-disabled module.
     registry_update();
     _system_update_bootstrap_status();
+    // Update the theme registry to remove the newly-disabled module.
+    drupal_theme_rebuild();
   }
 }
 
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 0c955e8..129762b 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -237,7 +237,7 @@ function _drupal_theme_initialize($theme, $base_theme = array(), $registry_callb
 /**
  * Get the theme registry.
  *
- * @param $complete
+ * @param bool $complete
  *   Optional boolean to indicate whether to return the complete theme registry
  *   array or an instance of the ThemeRegistry class. If TRUE, the complete
  *   theme registry array will be returned. This is useful if you want to
@@ -252,7 +252,20 @@ function _drupal_theme_initialize($theme, $base_theme = array(), $registry_callb
  *   class.
  */
 function theme_get_registry($complete = TRUE) {
-  static $theme_registry = array();
+  // Use the advanced drupal_static() pattern, since this is called very often.
+  static $drupal_static_fast;
+  if (!isset($drupal_static_fast)) {
+    $drupal_static_fast['registry'] = &drupal_static('theme_get_registry');
+  }
+  $theme_registry = $drupal_static_fast['registry'];
+
+  // Initialize the theme, if this is called early in the bootstrap, or after
+  // static variables have been reset.
+  if (!is_array($theme_registry)) {
+    drupal_theme_initialize();
+    $theme_registry = array();
+  }
+
   $key = (int) $complete;
 
   if (!isset($theme_registry[$key])) {
@@ -336,6 +349,7 @@ function _theme_save_registry($theme, $registry) {
  */
 function drupal_theme_rebuild() {
   cache()->deletePrefix('theme_registry');
+  drupal_static_reset('theme_get_registry');
 }
 
 /**
@@ -899,8 +913,6 @@ function list_themes($refresh = FALSE) {
  * @see themeable
  */
 function theme($hook, $variables = array()) {
-  static $hooks = NULL;
-
   // If called before all modules are loaded, we do not necessarily have a full
   // theme registry to work with, and therefore cannot process the theme
   // request properly. See also _theme_load_registry().
@@ -908,10 +920,7 @@ function theme($hook, $variables = array()) {
     throw new Exception(t('theme() may not be called until all modules are loaded.'));
   }
 
-  if (!isset($hooks)) {
-    drupal_theme_initialize();
-    $hooks = theme_get_registry(FALSE);
-  }
+  $hooks = theme_get_registry(FALSE);
 
   // If an array of hook candidates were passed, use the first one that has an
   // implementation.
diff --git a/core/modules/simpletest/tests/theme.test b/core/modules/simpletest/tests/theme.test
index 9870545..1f37aac 100644
--- a/core/modules/simpletest/tests/theme.test
+++ b/core/modules/simpletest/tests/theme.test
@@ -113,6 +113,20 @@ class ThemeUnitTest extends DrupalWebTestCase {
     $this->drupalGet('theme-test/template-test');
     $this->assertText('Success: Template overridden.', t('Template overridden by defined \'template\' filename.'));
   }
+
+  /**
+   * Ensures the theme registry is rebuilt when modules are disabled/enabled.
+   */
+  function testRegistryRebuild() {
+    $this->assertIdentical(theme('theme_test_foo', array('foo' => 'a')), 'a', t('The theme registry contains theme_test_foo.'));
+
+    module_disable(array('theme_test'), FALSE);
+    $this->assertIdentical(theme('theme_test_foo', array('foo' => 'b')), '');
+    $this->assertIdentical(theme('theme_test_foo', array('foo' => 'b')), '', t('The theme registry does not contain theme_test_foo, because the module is disabled.'));
+
+    module_enable(array('theme_test'), FALSE);
+    $this->assertIdentical(theme('theme_test_foo', array('foo' => 'c')), 'c', t('The theme registry contains theme_test_foo again after re-enabling the module.'));
+  }
 }
 
 /**
diff --git a/core/modules/simpletest/tests/theme_test.module b/core/modules/simpletest/tests/theme_test.module
index 570b72c..4c3d9e9 100644
--- a/core/modules/simpletest/tests/theme_test.module
+++ b/core/modules/simpletest/tests/theme_test.module
@@ -10,6 +10,9 @@ function theme_test_theme($existing, $type, $theme, $path) {
   $items['theme_test_template_test_2'] = array(
     'template' => 'theme_test.template_test',
   );
+  $items['theme_test_foo'] = array(
+    'variables' => array('foo' => NULL),
+  );
 
   return $items;
 }
@@ -131,6 +134,13 @@ function _theme_test_suggestion() {
 }
 
 /**
+ * Theme function for testing theme('theme_test_foo').
+ */
+function theme_theme_test_foo($variables) {
+  return $variables['foo'];
+}
+
+/**
  * Implements hook_preprocess_breadcrumb().
  *
  * Set a variable that can later be tested to see if this function ran.
