diff --git a/includes/common.inc b/includes/common.inc
index 90be49c5ac29141221c468d3274290a3c46d1892..2a93e79997d1a818f9726bda6a377e739c4b4453 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -4520,6 +4520,22 @@ function drupal_alter($type, &$data, &$context1 = NULL, &$context2 = NULL) {
     $function = $module . '_' . $hook;
     $function($data, $context1, $context2);
   }
+  // Allow the theme to alter variables after the theme system has been
+  // initialized.
+  global $theme, $base_theme_info;
+  if (isset($theme)) {
+    $theme_keys = array();
+    foreach ($base_theme_info as $base) {
+      $theme_keys[] = $base->name;
+    }
+    $theme_keys[] = $theme;
+    foreach ($theme_keys as $theme_key) {
+      $function = $theme_key . '_' . $hook;
+      if (function_exists($function)) {
+        $function($data, $context1, $context2);
+      }
+    }
+  }
 }
 
 /**
diff --git a/includes/theme.maintenance.inc b/includes/theme.maintenance.inc
index a625e15c0c9b96f2b33184b8a060b10506edffe0..5ba1ee3ac81178105c5fbd94b46b465a9587b9a2 100644
--- a/includes/theme.maintenance.inc
+++ b/includes/theme.maintenance.inc
@@ -33,7 +33,7 @@ function _drupal_maintenance_theme() {
 
   // Install and update pages are treated differently to prevent theming overrides.
   if (defined('MAINTENANCE_MODE') && (MAINTENANCE_MODE == 'install' || MAINTENANCE_MODE == 'update')) {
-    $theme = 'minnelli';
+    $custom_theme = 'minnelli';
   }
   else {
     if (!db_is_active()) {
@@ -46,11 +46,16 @@ function _drupal_maintenance_theme() {
       drupal_load('module', 'filter');
     }
 
-    $theme = variable_get('maintenance_theme', 'minnelli');
+    $custom_theme = variable_get('maintenance_theme', 'minnelli');
   }
 
   $themes = list_themes();
 
+  // list_themes() triggers a drupal_alter() in maintenance mode, but we can't
+  // let themes alter the .info data until we know a theme's base themes. So
+  // don't set global $theme until after list_themes() builds its cache.
+  $theme = $custom_theme;
+
   // Store the identifier for retrieving theme settings with.
   $theme_key = $theme;
 
diff --git a/modules/simpletest/tests/common.test b/modules/simpletest/tests/common.test
index 55b4b43326471c3494f36464737aa7e6300cfdf5..135ca18cb174b9bf328863cf1c6c83e8e5bd0460 100644
--- a/modules/simpletest/tests/common.test
+++ b/modules/simpletest/tests/common.test
@@ -29,24 +29,24 @@ class DrupalAlterTestCase extends DrupalWebTestCase {
 
     // Verify alteration of a single argument.
     $array_copy = $array;
-    $array_expected = array('foo' => 'Drupal');
+    $array_expected = array('foo' => 'Drupal theme');
     drupal_alter('drupal_alter', $array_copy);
     $this->assertEqual($array_copy, $array_expected, t('Single array was altered.'));
 
     $object_copy = clone $object;
     $object_expected = clone $object;
-    $object_expected->foo = 'Drupal';
+    $object_expected->foo = 'Drupal theme';
     drupal_alter('drupal_alter', $object_copy);
     $this->assertEqual($object_copy, $object_expected, t('Single object was altered.'));
 
     // Verify alteration of multiple arguments.
     $array_copy = $array;
-    $array_expected = array('foo' => 'Drupal');
+    $array_expected = array('foo' => 'Drupal theme');
     $object_copy = clone $object;
     $object_expected = clone $object;
-    $object_expected->foo = 'Drupal';
+    $object_expected->foo = 'Drupal theme';
     $array2_copy = $array;
-    $array2_expected = array('foo' => 'Drupal');
+    $array2_expected = array('foo' => 'Drupal theme');
     drupal_alter('drupal_alter', $array_copy, $object_copy, $array2_copy);
     $this->assertEqual($array_copy, $array_expected, t('First argument to drupal_alter() was altered.'));
     $this->assertEqual($object_copy, $object_expected, t('Second argument to drupal_alter() was altered.'));
diff --git a/modules/simpletest/tests/common_test.module b/modules/simpletest/tests/common_test.module
index cc8c2277232b82c81fa16758df41d8e3fb223fd1..e8c6602c23ee79c2fa62a22456118b761e78ab1c 100644
--- a/modules/simpletest/tests/common_test.module
+++ b/modules/simpletest/tests/common_test.module
@@ -100,6 +100,40 @@ function common_test_drupal_alter_alter(&$data, &$arg2 = NULL, &$arg3 = NULL) {
   }
 }
 
+/**
+ * Implement hook_TYPE_alter() on behalf of Garland theme.
+ *
+ * Same as common_test_drupal_alter_alter(), but here, we verify that themes
+ * can also alter and come last.
+ */
+function garland_drupal_alter_alter(&$data, &$arg2 = NULL, &$arg3 = NULL) {
+  // Alter first argument.
+  if (is_array($data)) {
+    $data['foo'] .= ' theme';
+  }
+  elseif (is_object($data)) {
+    $data->foo .= ' theme';
+  }
+  // Alter second argument, if present.
+  if (isset($arg2)) {
+    if (is_array($arg2)) {
+      $arg2['foo'] .= ' theme';
+    }
+    elseif (is_object($arg2)) {
+      $arg2->foo .= ' theme';
+    }
+  }
+  // Try to alter third argument, if present.
+  if (isset($arg3)) {
+    if (is_array($arg3)) {
+      $arg3['foo'] .= ' theme';
+    }
+    elseif (is_object($arg3)) {
+      $arg3->foo .= ' theme';
+    }
+  }
+}
+
 /**
  * Implement hook_theme().
  */