diff --git a/core/lib/Drupal/Core/Theme/ThemeManager.php b/core/lib/Drupal/Core/Theme/ThemeManager.php
index 0cbd529..466b07f 100644
--- a/core/lib/Drupal/Core/Theme/ThemeManager.php
+++ b/core/lib/Drupal/Core/Theme/ThemeManager.php
@@ -145,48 +145,52 @@ public function render($hook, array $variables) {
     }
 
     $theme_registry = $this->themeRegistry->getRuntime();
-
-    // If an array of hook candidates were passed, use the first one that has an
-    // implementation.
-    if (is_array($hook)) {
-      foreach ($hook as $candidate) {
-        if ($theme_registry->has($candidate)) {
-          break;
-        }
+    // All theme hooks are converted into an array. Save info to be used later
+    // whether conversion has happened.
+    $hook_is_array = is_array($hook);
+    $theme_hooks = (array) $hook;
+    $hook_found = FALSE;
+    // Check for hook implementation. If an array of hook candidates were
+    // passed, use the first one that has an implementation.
+    foreach ($theme_hooks as $candidate) {
+      if ($hook_found = $theme_registry->has($candidate)) {
+        break;
       }
-      $hook = $candidate;
     }
+    $hook = $candidate;
     // Save the original theme hook, so it can be supplied to theme variable
     // preprocess callbacks.
     $original_hook = $hook;
 
-    // If there's no implementation, check for more generic fallbacks.
-    // If there's still no implementation, log an error and return an empty
-    // string.
-    if (!$theme_registry->has($hook)) {
-      // Iteratively strip everything after the last '__' delimiter, until an
-      // implementation is found.
-      while ($pos = strrpos($hook, '__')) {
-        $hook = substr($hook, 0, $pos);
-        if ($theme_registry->has($hook)) {
-          break;
-        }
+    $derived_hooks = [];
+    // Remove the last item of the array which is the original hook and use it
+    // as a pattern.
+    $hook_pattern = array_pop($theme_hooks);
+    // Get the generic fallbacks. If a valid hook implementation has not been
+    // found, check each fallback until one is.
+    while ($pos = strrpos($hook_pattern, '__')) {
+      // Save all derived hooks to be used later as a theme suggestion.
+      $derived_hooks[] = $hook_pattern;
+      $hook_pattern = substr($hook_pattern, 0, $pos);
+      if (!$hook_found && $hook_found = $theme_registry->has($hook_pattern)) {
+        $hook = $hook_pattern;
       }
-      if (!$theme_registry->has($hook)) {
-        // Only log a message when not trying theme suggestions ($hook being an
-        // array).
-        if (!isset($candidate)) {
-          \Drupal::logger('theme')->warning('Theme hook %hook not found.', array('%hook' => $hook));
-        }
-        // There is no theme implementation for the hook passed. Return FALSE so
-        // the function calling
-        // \Drupal\Core\Theme\ThemeManagerInterface::render() can differentiate
-        // between a hook that exists and renders an empty string, and a hook
-        // that is not implemented.
-        return FALSE;
+    }
+    if (!$hook_found) {
+      // Only log a message when not trying theme suggestions ($hook being an
+      // array).
+      if (!$hook_is_array) {
+        \Drupal::logger('theme')->warning('Theme hook %hook not found.', array('%hook' => $hook));
       }
+      // There is no theme implementation for the hook passed. Return FALSE so
+      // the function calling
+      // \Drupal\Core\Theme\ThemeManagerInterface::render() can differentiate
+      // between a hook that exists and renders an empty string, and a hook
+      // that is not implemented.
+      return FALSE;
     }
 
+    $theme_hooks = array_merge($theme_hooks, $derived_hooks);
     $info = $theme_registry->get($hook);
 
     // If a renderable array is passed as $variables, then set $variables to
@@ -236,9 +240,7 @@ public function render($hook, array $variables) {
     // If the theme implementation was invoked with a direct theme suggestion
     // like '#theme' => 'node__article', add it to the suggestions array before
     // invoking suggestion alter hooks.
-    if (isset($info['base hook'])) {
-      $suggestions[] = $hook;
-    }
+    $suggestions = array_merge($suggestions, array_reverse($theme_hooks));
 
     // Invoke hook_theme_suggestions_alter() and
     // hook_theme_suggestions_HOOK_alter().
diff --git a/core/modules/system/src/Tests/Theme/ThemeSuggestionsAlterTest.php b/core/modules/system/src/Tests/Theme/ThemeSuggestionsAlterTest.php
index 1db3583..15962c2 100644
--- a/core/modules/system/src/Tests/Theme/ThemeSuggestionsAlterTest.php
+++ b/core/modules/system/src/Tests/Theme/ThemeSuggestionsAlterTest.php
@@ -157,6 +157,28 @@ public function testSuggestionsAlterInclude() {
   }
 
   /**
+   * Tests hook_theme_suggestions_HOOK() with direct array suggestions.
+   */
+  public function testArraySuggestions() {
+    $this->drupalGet('theme-test/array-suggestions');
+    $this->assertText('Template for testing suggestion hooks with an array of theme suggestions.');
+
+    // Enable the theme_suggestions_test module to test modules implementing
+    // suggestions hooks.
+    \Drupal::service('module_installer')->install(array('theme_suggestions_test'));
+
+    // Install test_theme to provide a template for the suggestion added in
+    // theme_suggestions_test module.
+    $this->config('system.theme')
+      ->set('default', 'test_theme')
+      ->save();
+
+    $this->resetAll();
+    $this->drupalGet('theme-test/array-suggestions');
+    $this->assertText('Template overridden based on new theme suggestion provided by a module via hook_theme_suggestions_HOOK().');
+  }
+
+  /**
    * Tests execution order of theme suggestion alter hooks.
    *
    * hook_theme_suggestions_alter() should fire before
diff --git a/core/modules/system/src/Tests/Theme/TwigDebugMarkupTest.php b/core/modules/system/src/Tests/Theme/TwigDebugMarkupTest.php
index c220dde..b1891f0 100644
--- a/core/modules/system/src/Tests/Theme/TwigDebugMarkupTest.php
+++ b/core/modules/system/src/Tests/Theme/TwigDebugMarkupTest.php
@@ -24,12 +24,11 @@ class TwigDebugMarkupTest extends WebTestBase {
   public static $modules = array('theme_test', 'node');
 
   /**
-   * Tests debug markup added to Twig template output.
+   * {@inheritdoc}
    */
-  function testTwigDebugMarkup() {
-    /** @var \Drupal\Core\Render\RendererInterface $renderer */
-    $renderer = $this->container->get('renderer');
-    $extension = twig_extension();
+  protected function setUp() {
+    parent::setUp();
+
     \Drupal::service('theme_handler')->install(array('test_theme'));
     \Drupal::service('theme_handler')->setDefault('test_theme');
     $this->drupalCreateContentType(array('type' => 'page'));
@@ -39,7 +38,15 @@ function testTwigDebugMarkup() {
     $this->setContainerParameter('twig.config', $parameters);
     $this->rebuildContainer();
     $this->resetAll();
+  }
 
+  /**
+   * Tests debug markup added to Twig template output.
+   */
+  public function testTwigDebugMarkup() {
+    /** @var \Drupal\Core\Render\RendererInterface $renderer */
+    $renderer = $this->container->get('renderer');
+    $extension = twig_extension();
     $cache = $this->container->get('theme.registry')->get();
     // Create array of Twig templates.
     $templates = drupal_find_theme_templates($cache, $extension, drupal_get_path('theme', 'test_theme'));
@@ -85,4 +92,65 @@ function testTwigDebugMarkup() {
     $this->assertFalse(strpos($output, '<!-- THEME DEBUG -->') !== FALSE, 'Twig debug markup not found in theme output when debug is disabled.');
   }
 
+  /**
+   * Tests debug markup for array suggestions and hook_theme_suggestions_HOOK().
+   */
+  public function testArraySuggestionsTwigDebugMarkup() {
+    \Drupal::service('module_installer')->install(array('theme_suggestions_test'));
+    $extension = twig_extension();
+    $this->drupalGet('theme-test/array-suggestions');
+    $output = $this->getRawContent();
+
+    $expected = "THEME HOOK: 'theme_test_array_suggestions'";
+    $this->assertTrue(strpos($output, $expected) !== FALSE, 'Theme call information found.');
+
+    $expected = '<!-- FILE NAME SUGGESTIONS:' . PHP_EOL
+      . '   * theme-test-array-suggestions--not-implemented' . $extension . PHP_EOL
+      . '   * theme-test-array-suggestions--not-implemented-2' . $extension . PHP_EOL
+      . '   x theme-test-array-suggestions--suggestion-from-hook' . $extension . PHP_EOL
+      . '   * theme-test-array-suggestions' . $extension . PHP_EOL
+      . '-->';
+    $message = 'Suggested template files found in order and correct suggestion shown as current template.';
+    $this->assertTrue(strpos($output, $expected) !== FALSE, $message);
+  }
+
+  /**
+   * Tests debug markup for specific suggestions without implementation.
+   */
+  public function testUnimplementedSpecificSuggestionsTwigDebugMarkup() {
+    $extension = twig_extension();
+    $this->drupalGet('theme-test/specific-suggestion');
+    $output = $this->getRawContent();
+
+    $expected = "THEME HOOK: 'theme_test_specific_suggestions__not__found'";
+    $this->assertTrue(strpos($output, $expected) !== FALSE, 'Theme call information found.');
+
+    $message = 'Suggested template files found in order and base template shown as current template.';
+    $expected = '<!-- FILE NAME SUGGESTIONS:' . PHP_EOL
+      . '   * theme-test-specific-suggestions--not--found' . $extension . PHP_EOL
+      . '   * theme-test-specific-suggestions--not' . $extension . PHP_EOL
+      . '   x theme-test-specific-suggestions' . $extension . PHP_EOL
+      . '-->';
+    $this->assertTrue(strpos($output, $expected) !== FALSE, $message);
+  }
+
+  /**
+   * Tests debug markup for specific suggestions.
+   */
+  public function testSpecificSuggestionsTwigDebugMarkup() {
+    $extension = twig_extension();
+    $this->drupalGet('theme-test/specific-suggestion-alter');
+    $output = $this->getRawContent();
+
+    $expected = "THEME HOOK: 'theme_test_specific_suggestions__variant'";
+    $this->assertTrue(strpos($output, $expected) !== FALSE, 'Theme call information found.');
+
+    $expected = '<!-- FILE NAME SUGGESTIONS:' . PHP_EOL
+      . '   x theme-test-specific-suggestions--variant' . $extension . PHP_EOL
+      . '   * theme-test-specific-suggestions' . $extension . PHP_EOL
+      . '-->';
+    $message = 'Suggested template files found in order and suggested template shown as current.';
+    $this->assertTrue(strpos($output, $expected) !== FALSE, $message);
+  }
+
 }
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 974856a..1d8cbf2 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
@@ -55,3 +55,10 @@ function theme_suggestions_test_theme_suggestions_theme_test_specific_suggestion
 function theme_suggestions_test_theme_suggestions_theme_test_suggestions_include_alter(array &$suggestions, array $variables, $hook) {
   $suggestions[] = 'theme_suggestions_test_include';
 }
+
+/**
+ * Implements hook_theme_suggestions_HOOK().
+ */
+function theme_suggestions_test_theme_suggestions_theme_test_array_suggestions(array $variables) {
+  return array('theme_test_array_suggestions__suggestion_from_hook');
+}
diff --git a/core/modules/system/tests/modules/theme_test/src/ThemeTestController.php b/core/modules/system/tests/modules/theme_test/src/ThemeTestController.php
index 68b627e..19ea986 100644
--- a/core/modules/system/tests/modules/theme_test/src/ThemeTestController.php
+++ b/core/modules/system/tests/modules/theme_test/src/ThemeTestController.php
@@ -111,6 +111,13 @@ function generalSuggestionAlter() {
   }
 
   /**
+   * Menu callback for testing direct suggestions without implementation.
+   */
+  public function specificSuggestion() {
+    return array('#theme' => 'theme_test_specific_suggestions__not__found');
+  }
+
+  /**
    * Menu callback for testing suggestion alter hooks with specific suggestions.
    */
   function specificSuggestionAlter() {
@@ -133,6 +140,19 @@ function suggestionAlterInclude() {
   }
 
   /**
+   * Menu callback for testing suggestion hooks with an array of theme hooks.
+   */
+  public function arraySuggestions() {
+    return array(
+      '#theme' => array(
+        'theme_test_array_suggestions__not_implemented',
+        'theme_test_array_suggestions__not_implemented_2',
+        'theme_test_array_suggestions',
+      ),
+    );
+  }
+
+  /**
    * Controller to ensure that no theme is initialized.
    *
    * @return \Symfony\Component\HttpFoundation\JsonResponse
diff --git a/core/modules/system/tests/modules/theme_test/templates/theme-test-array-suggestions.html.twig b/core/modules/system/tests/modules/theme_test/templates/theme-test-array-suggestions.html.twig
new file mode 100644
index 0000000..bb52340
--- /dev/null
+++ b/core/modules/system/tests/modules/theme_test/templates/theme-test-array-suggestions.html.twig
@@ -0,0 +1,2 @@
+{# Output for Theme API test #}
+Template for testing suggestion hooks with an array of theme suggestions.
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 540185e..68149aa 100644
--- a/core/modules/system/tests/modules/theme_test/theme_test.module
+++ b/core/modules/system/tests/modules/theme_test/theme_test.module
@@ -57,6 +57,9 @@ function theme_test_theme($existing, $type, $theme, $path) {
     'variables' => array(),
     'function' => 'theme_theme_test_function_template_override',
   );
+  $items['theme_test_array_suggestions'] = array(
+    'variables' => array(),
+  );
   $info['test_theme_not_existing_function'] = array(
     'function' => 'test_theme_not_existing_function',
   );
diff --git a/core/modules/system/tests/modules/theme_test/theme_test.routing.yml b/core/modules/system/tests/modules/theme_test/theme_test.routing.yml
index 1ff61cf..f5e65b5 100644
--- a/core/modules/system/tests/modules/theme_test/theme_test.routing.yml
+++ b/core/modules/system/tests/modules/theme_test/theme_test.routing.yml
@@ -76,6 +76,13 @@ suggestion_provided:
   requirements:
     _access: 'TRUE'
 
+theme_test.specific_suggestion:
+  path: '/theme-test/specific-suggestion'
+  defaults:
+    _controller: '\Drupal\theme_test\ThemeTestController::specificSuggestion'
+  requirements:
+    _access: 'TRUE'
+
 specific_suggestion_alter:
   path: '/theme-test/specific-suggestion-alter'
   defaults:
@@ -97,6 +104,13 @@ suggestion_alter_include:
   requirements:
     _access: 'TRUE'
 
+theme_test.array_suggestions:
+  path: '/theme-test/array-suggestions'
+  defaults:
+    _controller: '\Drupal\theme_test\ThemeTestController::arraySuggestions'
+  requirements:
+    _access: 'TRUE'
+
 theme_test.non_html:
   path: '/theme-test/non-html'
   defaults:
diff --git a/core/modules/system/tests/themes/test_theme/templates/theme-test-array-suggestions--suggestion-from-hook.html.twig b/core/modules/system/tests/themes/test_theme/templates/theme-test-array-suggestions--suggestion-from-hook.html.twig
new file mode 100644
index 0000000..2a00d59
--- /dev/null
+++ b/core/modules/system/tests/themes/test_theme/templates/theme-test-array-suggestions--suggestion-from-hook.html.twig
@@ -0,0 +1,2 @@
+{# Output for Theme API test #}
+Template overridden based on new theme suggestion provided by a module via hook_theme_suggestions_HOOK().
diff --git a/core/modules/views/src/Tests/ViewsThemeIntegrationTest.php b/core/modules/views/src/Tests/ViewsThemeIntegrationTest.php
index f6664e0..5373ed0 100644
--- a/core/modules/views/src/Tests/ViewsThemeIntegrationTest.php
+++ b/core/modules/views/src/Tests/ViewsThemeIntegrationTest.php
@@ -83,4 +83,32 @@ public function testThemedViewPage() {
     $this->assertRaw('<em class="placeholder">' . count($this->dataSet()) . '</em> items found.', 'Views group title added by test_subtheme.test_subtheme_views_post_render');
   }
 
+  /**
+   * Tests the views theme suggestions in debug mode.
+   */
+  public function testThemeSuggestionsInDebug() {
+    $parameters = $this->container->getParameter('twig.config');
+    $parameters['debug'] = TRUE;
+    $this->setContainerParameter('twig.config', $parameters);
+    $this->rebuildContainer();
+    $this->resetAll();
+
+    $build = [
+      '#type' => 'view',
+      '#name' => 'test_page_display',
+      '#display_id' => 'default',
+      '#arguments' => [],
+    ];
+
+    /** @var \Drupal\Core\Render\RendererInterface $renderer */
+    $renderer = $this->container->get('renderer');
+
+    $output = $renderer->renderRoot($build);
+    $expected = '   * views-view--test-page-display--default.html.twig' . PHP_EOL
+      . '   * views-view--default.html.twig' . PHP_EOL
+      . '   * views-view--test-page-display.html.twig' . PHP_EOL
+      . '   x views-view.html.twig' . PHP_EOL;
+    $this->assertTrue(strpos($output, $expected) !== FALSE);
+  }
+
 }
diff --git a/core/themes/engines/twig/twig.engine b/core/themes/engines/twig/twig.engine
index f4e18f5..6637808 100644
--- a/core/themes/engines/twig/twig.engine
+++ b/core/themes/engines/twig/twig.engine
@@ -82,31 +82,18 @@ function twig_render_template($template_file, array $variables) {
     // If there are theme suggestions, reverse the array so more specific
     // suggestions are shown first.
     if (!empty($variables['theme_hook_suggestions'])) {
-      $variables['theme_hook_suggestions'] = array_reverse($variables['theme_hook_suggestions']);
-    }
-    // Add debug output for directly called suggestions like
-    // '#theme' => 'comment__node__article'.
-    if (strpos($variables['theme_hook_original'], '__') !== FALSE) {
-      $derived_suggestions[] = $hook = $variables['theme_hook_original'];
-      while ($pos = strrpos($hook, '__')) {
-        $hook = substr($hook, 0, $pos);
-        $derived_suggestions[] = $hook;
-      }
-      // Get the value of the base hook (last derived suggestion) and append it
-      // to the end of all theme suggestions.
-      $base_hook = array_pop($derived_suggestions);
-      $variables['theme_hook_suggestions'] = array_merge($derived_suggestions, $variables['theme_hook_suggestions']);
-      $variables['theme_hook_suggestions'][] = $base_hook;
-    }
-    if (!empty($variables['theme_hook_suggestions'])) {
+      $suggestions = array_reverse($variables['theme_hook_suggestions']);
       $extension = twig_extension();
       $current_template = basename($template_file);
-      $suggestions = $variables['theme_hook_suggestions'];
-      // Only add the original theme hook if it wasn't a directly called
-      // suggestion.
-      if (strpos($variables['theme_hook_original'], '__') === FALSE) {
+      $pos = strpos($variables['theme_hook_original'], '__');
+
+      if ($pos !== FALSE) {
+        $suggestions[] = substr($variables['theme_hook_original'], 0, $pos);
+      }
+      else {
         $suggestions[] = $variables['theme_hook_original'];
       }
+
       foreach ($suggestions as &$suggestion) {
         $template = strtr($suggestion, '_', '-') . $extension;
         $prefix = ($template == $current_template) ? 'x' : '*';
