diff --git a/core/includes/common.inc b/core/includes/common.inc
index 0f252cacfd62728a080deaace023a7ce2bf4b3aa..092ac111ae449fbb6dd533dfdff2c12a6545f176 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -6557,7 +6557,7 @@ function drupal_array_nested_key_exists(array $array, array $parents) {
  * - description: Brief description.
  * - screenshot: Path to screenshot relative to the theme's .info file.
  * - engine: Theme engine; typically phptemplate.
- * - base: Name of a base theme, if applicable; e.g., base = zen.
+ * - base theme: Name of a base theme, if applicable; e.g., base theme = zen.
  * - regions: Listed regions; e.g., region[left] = Left sidebar.
  * - features: Features available; e.g., features[] = logo.
  * - stylesheets: Theme stylesheets; e.g., stylesheets[all][] = my-style.css.
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index da3909793590f1ad49a767c71813e941b148e4bf..bdbc9d793aaa8432b7c66ec90f2096282029e01a 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -1497,8 +1497,8 @@ function install_profile_modules(&$install_state) {
   $files[$install_state['parameters']['profile']]->info['required'] = FALSE;
   // Add modules that other modules depend on.
   foreach ($modules as $module) {
-    if ($files[$module]->requires) {
-      $modules = array_merge($modules, array_keys($files[$module]->requires));
+    if ($files[$module]->requires['modules']) {
+      $modules = array_merge($modules, array_keys($files[$module]->requires['modules']));
     }
   }
   $modules = array_unique($modules);
diff --git a/core/includes/module.inc b/core/includes/module.inc
index c1d99f238ffecbfd50a941d9833cb4e841f46dfd..b7721249890c01aec50e227c74cd0dc614bc6693 100644
--- a/core/includes/module.inc
+++ b/core/includes/module.inc
@@ -282,17 +282,19 @@ function system_list_reset() {
 }
 
 /**
- * Determines which modules require and are required by each module.
+ * Determines which modules require and are required by each file.
+ *
+ * Required modules are declared in an info file with "dependencies[] = foo".
  *
  * @param $files
  *   The array of filesystem objects used to rebuild the cache.
  *
  * @return
- *   The same array with the new keys for each module:
- *   - requires: An array with the keys being the modules that this module
+ *   The same array with the new keys for each file:
+ *   - requires: An array with the keys being the modules that this file
  *     requires.
  *   - required_by: An array with the keys being the modules that will not work
- *     without this module.
+ *     without this file.
  */
 function _module_build_dependencies($files) {
   foreach ($files as $filename => $file) {
@@ -307,8 +309,8 @@ function _module_build_dependencies($files) {
   $graph_object = new Graph($graph);
   $graph = $graph_object->searchAndSort();
   foreach ($graph as $module => $data) {
-    $files[$module]->required_by = isset($data['reverse_paths']) ? $data['reverse_paths'] : array();
-    $files[$module]->requires = isset($data['paths']) ? $data['paths'] : array();
+    $files[$module]->required_by['modules'] = isset($data['reverse_paths']) ? $data['reverse_paths'] : array();
+    $files[$module]->requires['modules'] = isset($data['paths']) ? $data['paths'] : array();
     $files[$module]->sort = $data['weight'];
   }
   return $files;
@@ -453,7 +455,7 @@ function module_enable($module_list, $enable_dependencies = TRUE) {
 
       // Add dependencies to the list, with a placeholder weight.
       // The new modules will be processed as the while loop continues.
-      foreach (array_keys($module_data[$module]->requires) as $dependency) {
+      foreach (array_keys($module_data[$module]->requires['modules']) as $dependency) {
         if (!isset($module_list[$dependency])) {
           $module_list[$dependency] = 0;
         }
@@ -592,7 +594,7 @@ function module_disable($module_list, $disable_dependents = TRUE) {
 
       // Add dependent modules to the list, with a placeholder weight.
       // The new modules will be processed as the while loop continues.
-      foreach ($module_data[$module]->required_by as $dependent => $dependent_data) {
+      foreach ($module_data[$module]->required_by['modules'] as $dependent => $dependent_data) {
         if (!isset($module_list[$dependent]) && $dependent != $profile) {
           $module_list[$dependent] = 0;
         }
@@ -673,7 +675,7 @@ function module_uninstall($module_list = array(), $uninstall_dependents = TRUE)
       // not included in the passed-in list, abort. It is not safe to uninstall
       // them automatically because uninstalling a module is a destructive
       // operation.
-      foreach (array_keys($module_data[$module]->required_by) as $dependent) {
+      foreach (array_keys($module_data[$module]->required_by['modules']) as $dependent) {
         if (!isset($module_list[$dependent]) && drupal_get_installed_schema_version($dependent) != SCHEMA_UNINSTALLED && $dependent != $profile) {
           return FALSE;
         }
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 3c4576ae07a36866963a57fc588881511ef0d1e2..3c2259677ac92332ce8c071ed3faae4f932016bc 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -11,6 +11,9 @@
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Template\Attribute;
 use Drupal\Core\Utility\ThemeRegistry;
+use Drupal\Component\Graph\Graph;
+use Drupal\Core\Config\DatabaseStorage;
+
 
 /**
  * @defgroup content_flags Content markers
@@ -2893,6 +2896,39 @@ function template_preprocess_region(&$variables) {
 }
 
 /**
+ * Determines which themes require and are required by each file.
+ *
+ * Required themes are declared in an info file with "base theme = foo".
+ *
+ * @param $files
+ *   The array of filesystem objects used to rebuild the cache.
+ *
+ * @return
+ *   The same array with the new keys for each file:
+ *   - requires: An array with the keys being the themes that this file
+ *     requires.
+ *   - required_by: An array with the keys being the themes that will not work
+ *     without this file.
+ */
+function _theme_build_dependencies($files) {
+  foreach ($files as $filename => $file) {
+    $graph[$file->name]['edges'] = array();
+    if (isset($file->info['base theme']) && is_string($file->info['base theme'])) {
+        $dependency_data = drupal_parse_dependency($file->info['base theme']);
+        $graph[$file->name]['edges'][$dependency_data['name']] = $dependency_data;
+    }
+  }
+  $graph_object = new Graph($graph);
+  $graph = $graph_object->searchAndSort();
+  foreach ($graph as $theme => $data) {
+    $files[$theme]->required_by['themes'] = isset($data['reverse_paths']) ? $data['reverse_paths'] : array();
+    $files[$theme]->requires['themes'] = isset($data['paths']) ? $data['paths'] : array();
+    $files[$theme]->sort = $data['weight'];
+  }
+  return $files;
+}
+
+/**
  * Provides theme registration for themes across .inc files.
  */
 function drupal_common_theme() {
diff --git a/core/modules/system/lib/Drupal/system/Tests/Module/EnableDisableTest.php b/core/modules/system/lib/Drupal/system/Tests/Module/EnableDisableTest.php
index f691e7a2e81c8edecb4656383973df858afe1866..66b726b9be1b55192840b470aca154ca0b3b1e83 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Module/EnableDisableTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Module/EnableDisableTest.php
@@ -72,7 +72,7 @@ function testEnableDisable() {
         // Find out if the module has any dependencies that aren't enabled yet;
         // if so, add them to the list of modules we expect to be automatically
         // enabled.
-        foreach (array_keys($module->requires) as $dependency) {
+        foreach (array_keys($module->requires['modules']) as $dependency) {
           if (isset($modules[$dependency]) && empty($automatically_enabled[$dependency])) {
             $modules_to_enable[] = $dependency;
             $automatically_enabled[$dependency] = TRUE;
diff --git a/core/modules/system/system.admin.css b/core/modules/system/system.admin.css
index 957d3e08d981f894e9524ddd632f232d80d72021..de49499d05e9e5e708ebdb5773fa6c83651477cd 100644
--- a/core/modules/system/system.admin.css
+++ b/core/modules/system/system.admin.css
@@ -207,6 +207,9 @@ table.screenshot {
 .system-themes-list-disabled .theme-info {
   min-height: 170px;
 }
+.theme-selector .theme-requires {
+ margin-bottom: 10px;
+}
 .theme-selector .incompatible {
   margin-top: 10px;
   font-weight: bold;
diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc
index c55289c366c3ab44df3d0d680e12e067bf982cec..a9b4d62d492d0fbe5d2a6fa8c7f273ddcd3914a4 100644
--- a/core/modules/system/system.admin.inc
+++ b/core/modules/system/system.admin.inc
@@ -221,7 +221,7 @@ function system_themes_page() {
     }
 
     // Sort enabled and disabled themes into their own groups.
-    $theme_groups[$theme->status ? 'enabled' : 'disabled'][] = $theme;
+    $theme_groups[$theme->status ? 'enabled' : 'disabled'][$theme->name] = $theme;
   }
 
   // There are two possible theme groups.
@@ -282,16 +282,37 @@ function system_theme_enable() {
     $theme = $_REQUEST['theme'];
     // Get current list of themes.
     $themes = list_themes();
+    $theme_deps = _theme_build_dependencies($themes);
 
     // Check if the specified theme is one recognized by the system.
     if (!empty($themes[$theme])) {
-      theme_enable(array($theme));
-      drupal_set_message(t('The %theme theme has been enabled.', array('%theme' => $themes[$theme]->info['name'])));
+      if ($theme_deps[$theme]->requires) {
+
+        $modules = $theme_deps[$theme]->requires;
+        $required = '<ul>';
+        foreach ($modules as $module) {
+          if ($module->status != 1) {
+            $required .= '<li>' . check_plain($module->name) . '</li>';
+          }
+        }
+
+        $output = '<div class="required">You must enable the following modules in order to enable ' . check_plain($themes[$theme]->info['name']) . ':</div>' . $required;
+
+        $output .= l(t('Cancel'), 'admin/appearance');
+        $output .= l(t('Enable'), 'admin/appearance/enable');
+
+        return $output;
+      }
+      else {
+        theme_enable(array($theme));
+        drupal_set_message(t('The %theme theme has been enabled.', array('%theme' => $themes[$theme]->info['name'])));
+        drupal_goto('admin/appearance');
+      }
     }
     else {
       drupal_set_message(t('The %theme theme was not found.', array('%theme' => $theme)), 'error');
+      drupal_goto('admin/appearance');
     }
-    drupal_goto('admin/appearance');
   }
   throw new AccessDeniedHttpException();
 }
@@ -828,7 +849,7 @@ function system_modules($form, $form_state = array()) {
     }
 
     // If this module requires other modules, add them to the array.
-    foreach ($module->requires as $requires => $v) {
+    foreach ($module->requires['modules'] as $requires => $v) {
       if (!isset($files[$requires])) {
         $extra['requires'][$requires] = t('@module (<span class="admin-missing">missing</span>)', array('@module' => drupal_ucfirst($requires)));
         $extra['disabled'] = TRUE;
@@ -896,7 +917,7 @@ function system_modules($form, $form_state = array()) {
 
     // If this module is required by other modules, list those, and then make it
     // impossible to disable this one.
-    foreach ($module->required_by as $required_by => $v) {
+    foreach ($module->required_by['modules'] as $required_by => $v) {
       // Hidden modules are unset already.
       if (isset($visible_files[$required_by])) {
         if ($files[$required_by]->status == 1 && $module->status == 1) {
@@ -1130,7 +1151,7 @@ function system_modules_submit($form, &$form_state) {
       // that are not in $dependencies variable so that the user can be alerted
       // in the confirmation form that more modules need to be enabled.
       $dependencies = array();
-      foreach (array_keys($files[$name]->requires) as $required) {
+      foreach (array_keys($files[$name]->requires['modules']) as $required) {
         if (empty($modules[$required]['enabled'])) {
           if (isset($files[$required])) {
             $dependencies[] = $files[$required]->info['name'];
@@ -1171,7 +1192,7 @@ function system_modules_submit($form, &$form_state) {
     if ($module['enabled'] && drupal_get_installed_schema_version($name) == SCHEMA_UNINSTALLED) {
       if (!drupal_check_module($name)) {
         $modules[$name]['enabled'] = FALSE;
-        foreach (array_keys($files[$name]->required_by) as $required_by) {
+        foreach (array_keys($files[$name]->required_by['modules']) as $required_by) {
           $modules[$required_by]['enabled'] = FALSE;
         }
       }
@@ -1276,7 +1297,7 @@ function system_modules_uninstall($form, $form_state = NULL) {
       // All modules which depend on this one must be uninstalled first, before
       // we can allow this module to be uninstalled. (The installation profile
       // is excluded from this list.)
-      foreach (array_keys($module->required_by) as $dependent) {
+      foreach (array_keys($module->required_by['modules']) as $dependent) {
         if ($dependent != $profile && drupal_get_installed_schema_version($dependent) != SCHEMA_UNINSTALLED) {
           $dependent_name = isset($all_modules[$dependent]->info['name']) ? $all_modules[$dependent]->info['name'] : $dependent;
           $form['modules'][$module->name]['#required_by'][] = $dependent_name;
@@ -2603,6 +2624,10 @@ function theme_system_modules_uninstall($variables) {
  * @ingroup themeable
  */
 function theme_system_themes_page($variables) {
+  // Get information about available themes and modules.
+  $themes = system_rebuild_theme_data();
+  $modules = system_rebuild_module_data();
+
   $theme_groups = $variables['theme_groups'];
 
   $output = '<div id="system-themes-page">';
@@ -2623,11 +2648,61 @@ function theme_system_themes_page($variables) {
       // Localize the theme description.
       $description = t($theme->info['description']);
 
+      // Required Modules
+      $requires = '';
+      $enabled_reqs = 0;
+      $disabled_reqs = 0;
+      $disabled_mods = '';
+      $missing_reqs = 0;
+      if (!empty($theme_dependencies[$theme->name]->requires['modules'])) {
+        $theme_reqs = $theme_dependencies[$theme->name]->requires['themes'];
+          $missing = array();
+          foreach ($theme_reqs as $dependency) {
+            $missing[$dependency['name']] = new stdClass();
+            $missing[$dependency['name']]->name = $dependency['name'];
+            $missing[$dependency['name']]->status = $system_module_data[$dependency['name']]->status;
+          }
+
+          $dep_string = array();
+          foreach ($missing as $dep) {
+            if (is_null($dep->status)) {
+              $dep_string[] = t('@module (<span class="admin-missing">missing</span>)', array('@module' => $dep->name));
+              $missing_reqs++;
+            }
+            elseif ($dep->status == 0) {
+              $dep_string[] = t('@module (<span class="admin-disabled">disabled</span>)', array('@module' => $dep->name));
+              $disabled_mods .= $dep->name . ', ';
+              $disabled_reqs++;
+            }
+            elseif ($dep->status == 1) {
+              $dep_string[] = t('@module (<span class="admin-enabled">enabled</span>)', array('@module' => $dep->name));
+              $enabled_reqs++;
+            }
+          }
+
+          $m_length = count($dep_string);
+          $dependencies = '';
+
+
+          for ($i = 0; $i < $m_length; $i++) {
+            if ($i == $m_length - 1) {
+              $dependencies .= $dep_string[$i];
+            }
+            else {
+              $dependencies .= $dep_string[$i] . ', ';
+            }
+          }
+          if ($m_length > 0) {
+            $requires .= '<div class="theme-requires">' . t('Required modules: !dependencies', array('!dependencies' => $dependencies)) . '</div>';
+          }
+      }
+
       // Style theme info
       $notes = count($theme->notes) ? ' (' . join(', ', $theme->notes) . ')' : '';
       $theme->classes[] = 'theme-selector';
       $theme->classes[] = 'clearfix';
-      $output .= '<div class="'. join(' ', $theme->classes) .'">' . $screenshot . '<div class="theme-info"><h3>' . $theme->info['name'] . ' ' . (isset($theme->info['version']) ? $theme->info['version'] : '') . $notes . '</h3><div class="theme-description">' . $description . '</div>';
+      $output .= '<div class="'. join(' ', $theme->classes) .'">' . $screenshot . '<div class="theme-info"><h3>' . $theme->info['name'] . ' ' . (isset($theme->info['version']) ? $theme->info['version'] : '') . $notes . '</h3>' . $requires . '<div class="theme-description">' . $description . '</div>';
+
 
       // Make sure to provide feedback on compatibility.
       if (!empty($theme->incompatible_core)) {
@@ -2640,11 +2715,19 @@ function theme_system_themes_page($variables) {
         $output .= '<div class="incompatible">' . t('This theme requires PHP version @php_required and is incompatible with PHP version !php_version.', array('@php_required' => $theme->info['php'], '!php_version' => phpversion())) . '</div>';
       }
       elseif (!empty($theme->incompatible_base)) {
-        $output .= '<div class="incompatible">' . t('This theme requires the base theme @base_theme to operate correctly.', array('@base_theme' => $theme->info['base theme'])) . '</div>';
+        if ($missing_reqs > 0) {
+          $output .= '<div class="incompatible">' . t('In order to enable this theme, you must install the missing modules and the base theme @base_theme.', array('@base_theme' => $theme->info['base theme'])) . '</div>';
+        }
+        else {
+          $output .= '<div class="incompatible">' . t('In order to enable this theme, you must install the base theme @base_theme.', array('@base_theme' => $theme->info['base theme'])) . '</div>';
+        }
       }
       elseif (!empty($theme->incompatible_engine)) {
         $output .= '<div class="incompatible">' . t('This theme requires the theme engine @theme_engine to operate correctly.', array('@theme_engine' => $theme->info['engine'])) . '</div>';
       }
+      elseif ($missing_reqs > 0) {
+        $output .= '<div class="incompatible">' . t('In order to enable this theme, you must install the missing modules') . '</div>';
+      }
       else {
         $output .= theme('links', array('links' => $theme->operations, 'attributes' => array('class' => array('operations', 'clearfix'))));
       }
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index b1cf3750173b064c7b95c7035740e5c8ed02feeb..e44cc6461c1c936a85e63dd840b6c4ad9b72c128 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -448,7 +448,7 @@ function system_requirements($phase) {
         $requirements['php']['severity'] = REQUIREMENT_ERROR;
       }
       // Check the module's required modules.
-      foreach ($file->requires as $requirement) {
+      foreach ($file->requires['modules'] as $requirement) {
         $required_module = $requirement['name'];
         // Check if the module exists.
         if (!isset($files[$required_module])) {
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index 255c669ab9a0ba85ab46aeb0f65041bb1267b443..83a5248ba436c583f2f8ff4bdfdb86f960832d66 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -2975,6 +2975,10 @@ function _system_rebuild_theme_data() {
     }
   }
 
+  // Get module and theme dependencies for each theme.
+  $themes = _module_build_dependencies($themes);
+  $themes = _theme_build_dependencies($themes);
+
   return $themes;
 }
 
@@ -2985,30 +2989,33 @@ function _system_rebuild_theme_data() {
  *   Array of all available themes and their data.
  */
 function system_rebuild_theme_data() {
-  $themes = _system_rebuild_theme_data();
-  ksort($themes);
-  // @todo This function has no business in determining/setting the status of
-  //   a theme, but various other functions expect it to return themes with a
-  //   $status property. system_list() stores the return value of this function
-  //   in state, and ensures to set/override the $status property for each theme
-  //   based on the current config. Remove this code when themes have a proper
-  //   installation status.
-  // @see http://drupal.org/node/1067408
-  $enabled_themes = config('system.theme')->get('enabled');
-  $files = array();
-  foreach ($themes as $name => $theme) {
-    $theme->status = (int) isset($enabled_themes[$name]);
-    $files[$name] = $theme->filename;
-  }
-  // Replace last known theme data state.
-  // @todo Obsolete with proper installation status for themes.
-  state()->set('system.theme.data', $themes);
-
-  // Store filenames to allow system_list() and drupal_get_filename() to
-  // retrieve them without having to rebuild or scan the filesystem.
-  state()->set('system.theme.files', $files);
+  $themes_cache = &drupal_static(__FUNCTION__);
+  if(!isset($themes_cache)) {
+    $themes = _system_rebuild_theme_data();
+    ksort($themes);
+    // @todo This function has no business in determining/setting the status of
+    //   a theme, but various other functions expect it to return themes with a
+    //   $status property. system_list() stores the return value of this function
+    //   in state, and ensures to set/override the $status property for each theme
+    //   based on the current config. Remove this code when themes have a proper
+    //   installation status.
+    // @see http://drupal.org/node/1067408
+    $enabled_themes = config('system.theme')->get('enabled');
+    $files = array();
+    foreach ($themes as $name => $theme) {
+      $theme->status = (int) isset($enabled_themes[$name]);
+      $files[$name] = $theme->filename;
+    }
+    // Replace last known theme data state.
+    // @todo Obsolete with proper installation status for themes.
+    state()->set('system.theme.data', $themes);
 
-  return $themes;
+    // Store filenames to allow system_list() and drupal_get_filename() to
+    // retrieve them without having to rebuild or scan the filesystem.
+    state()->set('system.theme.files', $files);
+    $themes_cache = $themes;
+  }
+  return $themes_cache;
 }
 
 /**
