diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 9545be7..69301d8 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -622,8 +622,14 @@ function theme($hook, $variables = array()) {
   if (isset($info['base hook'])) {
     $suggestions[] = $hook;
   }
-  // Allow suggestions to be altered via hook_theme_suggestions_HOOK_alter().
-  Drupal::moduleHandler()->alter('theme_suggestions_' . $base_theme_hook, $suggestions, $variables);
+
+  // Invoke hook_theme_suggestions_alter() and
+  // hook_theme_suggestions_HOOK_alter().
+  $hooks = array(
+    'theme_suggestions',
+    'theme_suggestions_' . $base_theme_hook,
+  );
+  \Drupal::moduleHandler()->alter($hooks, $suggestions, $variables, $base_theme_hook);
 
   // Check if each suggestion exists in the theme registry, and if so,
   // use it instead of the hook that theme() was called with. For example, a
diff --git a/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeSuggestionsAlterTest.php b/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeSuggestionsAlterTest.php
index 00cd008..6ded5e5 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeSuggestionsAlterTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeSuggestionsAlterTest.php
@@ -117,4 +117,35 @@ function testThemeFunctionSuggestionsAlter() {
     $this->assertText('Theme function overridden based on new theme suggestion provided by a module.');
   }
 
+  /**
+   * Tests execution order of theme suggestion alter hooks.
+   *
+   * hook_theme_suggestions_alter() should fire before
+   * hook_theme_suggestions_HOOK_alter() within an extension (module or theme).
+   */
+  function testExecutionOrder() {
+    // Enable our test theme and module.
+    config('system.theme')
+      ->set('default', 'test_theme')
+      ->save();
+    \Drupal::moduleHandler()->install(array('theme_suggestions_test'));
+
+    // Send two requests so that we get all the messages we've set via
+    // drupal_set_message().
+    $this->drupalGet('theme-test/suggestion-alter');
+    $this->drupalGet('theme-test/suggestion-alter');
+    // Ensure that the order is first by extension, then for a given extension,
+    // the hook-specific one after the generic one.
+    $expected = array(
+      'theme_suggestions_test_theme_suggestions_alter() executed.',
+      'theme_suggestions_test_theme_suggestions_theme_test_suggestions_alter() executed.',
+      'theme_test_theme_suggestions_alter() executed.',
+      'theme_test_theme_suggestions_theme_test_suggestions_alter() executed.',
+      'test_theme_theme_suggestions_alter() executed.',
+      'test_theme_theme_suggestions_theme_test_suggestions_alter() executed.',
+    );
+    $content = preg_replace('/\s+/', ' ', filter_xss($this->content, array()));
+    $this->assert(strpos($content, implode(' ', $expected)) !== FALSE, 'Suggestion alter hooks executed in the expected order.');
+  }
+
 }
diff --git a/core/modules/system/tests/modules/theme_suggestions_test/theme_suggestions_test.module b/core/modules/system/tests/modules/theme_suggestions_test/theme_suggestions_test.module
index 9ecaeeb..690422e 100644
--- a/core/modules/system/tests/modules/theme_suggestions_test/theme_suggestions_test.module
+++ b/core/modules/system/tests/modules/theme_suggestions_test/theme_suggestions_test.module
@@ -6,9 +6,17 @@
  */
 
 /**
+ * Implements hook_theme_suggestions_alter().
+ */
+function theme_suggestions_test_theme_suggestions_alter(array &$suggestions, array $variables, $hook) {
+  drupal_set_message(__FUNCTION__ . '() executed.');
+}
+
+/**
  * Implements hook_theme_suggestions_HOOK_alter().
  */
 function theme_suggestions_test_theme_suggestions_theme_test_suggestions_alter(array &$suggestions, array $variables) {
+  drupal_set_message(__FUNCTION__ . '() executed.');
   $suggestions[] = 'theme_test_suggestions__' . 'module_override';
 }
 
diff --git a/core/modules/system/tests/modules/theme_test/theme_test.module b/core/modules/system/tests/modules/theme_test/theme_test.module
index 52bff21..f83c4ca 100644
--- a/core/modules/system/tests/modules/theme_test/theme_test.module
+++ b/core/modules/system/tests/modules/theme_test/theme_test.module
@@ -155,3 +155,17 @@ function theme_theme_test_function_suggestions($variables) {
 function theme_test_theme_suggestions_theme_test_suggestion_provided(array $variables) {
   return array('theme_test_suggestion_provided__' . 'foo');
 }
+
+/**
+ * Implements hook_theme_suggestions_alter().
+ */
+function theme_test_theme_suggestions_alter(array &$suggestions, array $variables, $hook) {
+  drupal_set_message(__FUNCTION__ . '() executed.');
+}
+
+/**
+ * Implements hook_theme_suggestions_HOOK_alter().
+ */
+function theme_test_theme_suggestions_theme_test_suggestions_alter(array &$suggestions, array $variables) {
+  drupal_set_message(__FUNCTION__ . '() executed.');
+}
diff --git a/core/modules/system/tests/themes/test_theme/test_theme.theme b/core/modules/system/tests/themes/test_theme/test_theme.theme
index 9b10b2b..df30618 100644
--- a/core/modules/system/tests/themes/test_theme/test_theme.theme
+++ b/core/modules/system/tests/themes/test_theme/test_theme.theme
@@ -31,9 +31,17 @@ function test_theme_theme_test_alter_alter(&$data) {
 }
 
 /**
+ * Implements hook_theme_suggestions_alter().
+ */
+function test_theme_theme_suggestions_alter(array &$suggestions, array $variables, $hook) {
+  drupal_set_message(__FUNCTION__ . '() executed.');
+}
+
+/**
  * Implements hook_theme_suggestions_HOOK_alter().
  */
 function test_theme_theme_suggestions_theme_test_suggestions_alter(array &$suggestions, array $variables) {
+  drupal_set_message(__FUNCTION__ . '() executed.');
   // Theme alter hooks run after module alter hooks, so add this theme
   // suggestion to the beginning of the array so that the suggestion added by
   // the theme_suggestions_test module can be picked up when that module is
diff --git a/core/modules/system/theme.api.php b/core/modules/system/theme.api.php
index 34758da..f8fdda4 100644
--- a/core/modules/system/theme.api.php
+++ b/core/modules/system/theme.api.php
@@ -190,6 +190,54 @@ function hook_theme_suggestions_HOOK(array $variables) {
 }
 
 /**
+ * Alters named suggestions for all theme hooks.
+ *
+ * This hook is invoked for all theme hooks, if you are targeting a specific
+ * theme hook it's best to use hook_theme_suggestions_HOOK_alter().
+ *
+ * The call order is as follows: all existing suggestion alter functions are
+ * called for module A, then all for module B, etc., followed by all for any
+ * base theme(s), and finally for the active theme. The order is
+ * determined by system weight, then by extension (module or theme) name.
+ *
+ * Within each module or theme, suggestion alter hooks are called in the
+ * following order: first, hook_theme_suggestions_alter(); second,
+ * hook_theme_suggestions_HOOK_alter(). So, for each module or theme, the more
+ * general hooks are called first followed by the more specific.
+ *
+ * In the following example, we provide an alternative template suggestion to
+ * node and taxonomy term templates based on the user being logged in.
+ * @code
+ * function MYMODULE_theme_suggestions_alter(array &$suggestions, array $variables, $hook) {
+ *   if ($variables['logged_in'] && in_array($hook, array('node', 'taxonomy-term'))) {
+ *     $suggestions[] = $hook . '__' . 'logged_in';
+ *   }
+ * }
+ *
+ * @endcode
+ *
+ * @param array $suggestions
+ *   An array of alternate, more specific names for template files or theme
+ *   functions.
+ * @param array $variables
+ *   An array of variables passed to the theme hook. Note that this hook is
+ *   invoked before any variable preprocessing.
+ * @param string $hook
+ *   The base hook name. For example, if '#theme' => 'node__article' is called,
+ *   then $hook will be 'node', not 'node__article'. The specific hook called
+ *   (in this case 'node__article') is available in
+ *   $variables['theme_hook_original'].
+ *
+ * @return array
+ *   An array of theme suggestions.
+ *
+ * @see hook_theme_suggestions_HOOK_alter()
+ */
+function hook_theme_suggestions_alter(array $suggestions, array $variables, $hook) {
+  $suggestions[] = $hook . '__' . $variables['elements']['#langcode'];
+}
+
+/**
  * Alters named suggestions for a specific theme hook.
  *
  * This hook allows any module or theme to provide altenative theme function or
@@ -210,6 +258,7 @@ function hook_theme_suggestions_HOOK(array $variables) {
  *   An array of variables passed to the theme hook. Note that this hook is
  *   invoked before any preprocessing.
  *
+ * @see hook_theme_suggestions_alter()
  * @see hook_theme_suggestions_HOOK()
  */
 function hook_theme_suggestions_HOOK_alter(array &$suggestions, array $variables) {
