diff --git a/includes/common.inc b/includes/common.inc
index 959675f8b87cfe5e5d680e713101857eacf8be39..afb08eafd4b59cbeb3eb06641ba0cd358235ef61 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -4592,13 +4592,19 @@ function _drupal_bootstrap_full() {
 
   // Initialize $_GET['q'] prior to invoking hook_init().
   drupal_path_initialize();
-  // Set a custom theme for the current page, if there is one. We need to run
-  // this before invoking hook_init(), since any modules which initialize the
-  // theme system will prevent a custom theme from being correctly set later.
-  menu_set_custom_theme();
-  // Let all modules take action before menu system handles the request
+
+  // Let all modules take action before the menu system handles the request.
   // We do not want this while running update.php.
   if (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update') {
+    // Prior to invoking hook_init(), initialize the theme (potentially a custom
+    // one for this page), so that:
+    // - Modules with hook_init() implementations that call theme() or
+    //   theme_get_registry() don't initialize the incorrect theme.
+    // - The theme can have hook_*_alter() implementations affect page building
+    //   (e.g., hook_form_alter(), hook_node_view_alter(), hook_page_alter()),
+    //   ahead of when rendering starts.
+    menu_set_custom_theme();
+    drupal_theme_initialize();
     module_invoke_all('init');
   }
 }
diff --git a/includes/theme.inc b/includes/theme.inc
index eb7111a4788bf03ce69ce19a2b5c381a03121f0a..a696117cf86fc5b499c1b221a1516baeec4c5f0d 100644
--- a/includes/theme.inc
+++ b/includes/theme.inc
@@ -221,8 +221,8 @@ function _drupal_theme_initialize($theme, $base_theme = array(), $registry_callb
     }
   }
 
-  if (function_exists($registry_callback)) {
-    $registry_callback($theme, $base_theme, $theme_engine);
+  if (isset($registry_callback)) {
+    _theme_registry_callback($registry_callback, array($theme, $base_theme, $theme_engine));
   }
 }
 
@@ -233,26 +233,30 @@ function _drupal_theme_initialize($theme, $base_theme = array(), $registry_callb
  *   The theme registry array if it has been stored in memory, NULL otherwise.
  */
 function theme_get_registry() {
-  return _theme_set_registry();
+  static $theme_registry = NULL;
+
+  if (!isset($theme_registry)) {
+    list($callback, $arguments) = _theme_registry_callback();
+    $theme_registry = call_user_func_array($callback, $arguments);
+  }
+
+  return $theme_registry;
 }
 
 /**
- * Store the theme registry in memory.
- *
- * @param $registry
- *   A registry array as returned by _theme_build_registry()
+ * Set the callback that will be used by theme_get_registry() to fetch the registry.
  *
- * @return
- *   The theme registry array stored in memory
+ * @param $callback
+ *   The name of the callback function.
+ * @param $arguments
+ *   The arguments to pass to the function.
  */
-function _theme_set_registry($registry = NULL) {
-  static $theme_registry = NULL;
-
-  if (isset($registry)) {
-    $theme_registry = $registry;
+function _theme_registry_callback($callback = NULL, array $arguments = array()) {
+  static $stored;
+  if (isset($callback)) {
+    $stored = array($callback, $arguments);
   }
-
-  return $theme_registry;
+  return $stored;
 }
 
 /**
@@ -271,7 +275,6 @@ function _theme_load_registry($theme, $base_theme = NULL, $theme_engine = NULL)
   $cache = cache_get("theme_registry:$theme->name", 'cache');
   if (isset($cache->data)) {
     $registry = $cache->data;
-    _theme_set_registry($registry);
   }
   else {
     // If not, build one and cache it.
@@ -280,9 +283,9 @@ function _theme_load_registry($theme, $base_theme = NULL, $theme_engine = NULL)
    // complete set of theme hooks.
     if (module_load_all(NULL)) {
       _theme_save_registry($theme, $registry);
-      _theme_set_registry($registry);
     }
   }
+  return $registry;
 }
 
 /**
diff --git a/includes/theme.maintenance.inc b/includes/theme.maintenance.inc
index 927499a8f3b7e29b4d651cace008305c21029081..419d300f192546a5d29c3bd1f41088130c485de6 100644
--- a/includes/theme.maintenance.inc
+++ b/includes/theme.maintenance.inc
@@ -88,8 +88,7 @@ function _drupal_maintenance_theme() {
  * This builds the registry when the site needs to bypass any database calls.
  */
 function _theme_load_offline_registry($theme, $base_theme = NULL, $theme_engine = NULL) {
-  $registry = _theme_build_registry($theme, $base_theme, $theme_engine);
-  _theme_set_registry($registry);
+  return _theme_build_registry($theme, $base_theme, $theme_engine);
 }
 
 /**
diff --git a/modules/simpletest/tests/theme.test b/modules/simpletest/tests/theme.test
index d4dc89842589663d8f0a365cad9e018915a750bd..f6dea3309085178bdfa57d65d2c169b59c199aa4 100644
--- a/modules/simpletest/tests/theme.test
+++ b/modules/simpletest/tests/theme.test
@@ -66,6 +66,14 @@ class ThemeUnitTest extends DrupalWebTestCase {
     $_GET['q'] = $q;
     $this->assertTrue(in_array('page__front', $suggestions), t('Front page template was suggested.'));
   }
+
+  /**
+   * Ensures theme hook_*_alter() implementations can run before anything is rendered.
+   */
+  function testAlter() {
+    $this->drupalGet('theme-test/alter');
+    $this->assertText('The altered data is test_theme_theme_test_alter_alter was invoked.', t('The theme was able to implement an alter hook during page building before anything was rendered.'));
+  }
 }
 
 /**
@@ -181,3 +189,30 @@ class ThemeHookInitUnitTest extends DrupalWebTestCase {
     $this->assertRaw('bartik/css/style.css', t("The default theme's CSS appears on the page when the theme system is initialized in hook_init()."));
   }
 }
+
+/**
+ * Tests autocompletion not loading registry.
+ */
+class ThemeFastTestCase extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Theme fast initialization',
+      'description' => 'Test that autocompletion does not load the registry.',
+      'group' => 'Theme'
+    );
+  }
+
+  function setUp() {
+    parent::setUp('theme_test');
+    $this->account = $this->drupalCreateUser(array('access user profiles'));
+  }
+
+  /**
+   * Tests access to user autocompletion and verify the correct results.
+   */
+  function testUserAutocomplete() {
+    $this->drupalLogin($this->account);
+    $this->drupalGet('user/autocomplete/' . $this->account->name);
+    $this->assertText('registry not initialized', t('The registry was not initialized'));
+  }
+}
diff --git a/modules/simpletest/tests/theme_test.module b/modules/simpletest/tests/theme_test.module
index ad22367b831424326365a60ced883c47a5cc4db1..ff525ec34188cf6b95031805383364094509e492 100644
--- a/modules/simpletest/tests/theme_test.module
+++ b/modules/simpletest/tests/theme_test.module
@@ -12,6 +12,13 @@ function theme_test_menu() {
     'theme callback' => '_theme_custom_theme',
     'type' => MENU_CALLBACK,
   );
+  $items['theme-test/alter'] = array(
+    'title' => 'Suggestion',
+    'page callback' => '_theme_test_alter',
+    'access arguments' => array('access content'),
+    'theme callback' => '_theme_custom_theme',
+    'type' => MENU_CALLBACK,
+  );
   $items['theme-test/hook-init'] = array(
     'page callback' => 'theme_test_hook_init_page_callback',
     'access callback' => TRUE,
@@ -24,15 +31,36 @@ function theme_test_menu() {
  * Implements hook_init().
  */
 function theme_test_init() {
-  // First, force the theme registry to be rebuilt on this page request. This
-  // allows us to test a full initialization of the theme system in the code
-  // below.
-  drupal_theme_rebuild();
-  // Next, initialize the theme system by storing themed text in a global
-  // variable. We will use this later in theme_test_hook_init_page_callback()
-  // to test that even when the theme system is initialized this early, it is
-  // still capable of returning output and theming the page as a whole.
-  $GLOBALS['theme_test_output'] = theme('more_link', array('url' => 'user', 'title' => 'Themed output generated in hook_init()'));
+  if (arg(0) == 'theme-test' && arg(1) == 'hook-init') {
+    // First, force the theme registry to be rebuilt on this page request. This
+    // allows us to test a full initialization of the theme system in the code
+    // below.
+    drupal_theme_rebuild();
+    // Next, initialize the theme system by storing themed text in a global
+    // variable. We will use this later in theme_test_hook_init_page_callback()
+    // to test that even when the theme system is initialized this early, it is
+    // still capable of returning output and theming the page as a whole.
+    $GLOBALS['theme_test_output'] = theme('more_link', array('url' => 'user', 'title' => 'Themed output generated in hook_init()'));
+  }
+}
+
+/**
+ * Implements hook_exit().
+ */
+function theme_test_exit() {
+  if (arg(0) == 'user') {
+    // Register a fake registry loading callback. If it gets called by
+    // theme_get_registry(), the registry has not been initialized yet.
+    _theme_registry_callback('_theme_test_load_registry', array());
+    print theme_get_registry() ? 'registry initialized' : 'registry not initialized';
+  }
+}
+
+/**
+ * Fake registry loading callback.
+ */
+function _theme_test_load_registry() {
+  return array();
 }
 
 /**
@@ -49,6 +77,19 @@ function _theme_custom_theme() {
   return 'test_theme';
 }
 
+/**
+ * Page callback, calls drupal_alter().
+ *
+ * This is for testing that the theme can have hook_*_alter() implementations
+ * that run during page callback execution, even before theme() is called for
+ * the first time.
+ */
+function _theme_test_alter() {
+  $data = 'foo';
+  drupal_alter('theme_test_alter', $data);
+  return "The altered data is $data.";
+}
+
 /**
  * Page callback, calls a theme hook suggestion.
  */
diff --git a/themes/tests/test_theme/template.php b/themes/tests/test_theme/template.php
index 944c2369011cb9fadb0971084f540604dc7b3b36..3d8b656c71fdd7dd78902eb24f098e61ef3fda0b 100644
--- a/themes/tests/test_theme/template.php
+++ b/themes/tests/test_theme/template.php
@@ -9,3 +9,14 @@ function test_theme_breadcrumb__suggestion($variables) {
   // when the suggestion has an implementation.
   return 'test_theme_breadcrumb__suggestion: ' . $variables['theme_test_preprocess_breadcrumb'];
 }
+
+/**
+ * Tests a theme implementing an alter hook.
+ *
+ * The confusing function name here is due to this being an implementation of
+ * the alter hook invoked when the 'theme_test' module calls
+ * drupal_alter('theme_test_alter').
+ */
+function test_theme_theme_test_alter_alter(&$data) {
+  $data = 'test_theme_theme_test_alter_alter was invoked';
+}