diff --git a/core/core.services.yml b/core/core.services.yml
index 40c6a8a..caff16d 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -1567,6 +1567,8 @@ services:
     arguments: ['@renderer', '@url_generator', '@theme.manager', '@date.formatter']
     tags:
       - { name: twig.extension, priority: 100 }
+      calls:
+        - [setThemeRegistry, ['@theme.registry']]
   # @todo Figure out what to do about debugging functions.
   # @see https://www.drupal.org/node/1804998
   twig.extension.debug:
diff --git a/core/lib/Drupal/Core/Template/ThemeRegistryNodeVisitor.php b/core/lib/Drupal/Core/Template/ThemeRegistryNodeVisitor.php
new file mode 100644
index 0000000..8f65170
--- /dev/null
+++ b/core/lib/Drupal/Core/Template/ThemeRegistryNodeVisitor.php
@@ -0,0 +1,192 @@
+<?php
+
+namespace Drupal\Core\Template;
+
+use Drupal\Core\Theme\Registry;
+
+/**
+ * Provides a Twig_NodeVisitor to change the generated parse-tree.
+ *
+ * This is used to ensure that templates in themes can extend parent templates
+ * without having to specify which theme that parent template lives in.
+ *
+ * Only updates expressions like:
+ * - {% extends "block.html.twig" %}
+ * - {% extends "block--search-form-block.html.twig" %}
+ *
+ * Does not update expressions like:
+ * - {% extends "@stable/block.twig" %}
+ * - {% extends "@stable/block--search-form-block.html.twig" %}
+ * - {% extends "path/to/block.html.twig" %}
+ * - {% extends "path/to/block--search-form-block.html.twig" %}
+ *
+ * Ensures that a variant of a theme hook that extends the non-variant does not
+ * skip the current theme's template: if a theme has
+ * block--search-form-block.html.twig that's extending block.html.twig, then it
+ * will use the current theme's block.html.twig if it has it, and not the parent
+ * theme's. This matches the behavior outside of Twig.
+ *
+ * @see https://www.drupal.org/node/2387069
+ * @see http://twig.sensiolabs.org/doc/tags/extends.html#dynamic-inheritance
+ *
+ * @see twig_render
+ */
+class ThemeRegistryNodeVisitor extends \Twig_BaseNodeVisitor {
+
+  /**
+   * The theme registry.
+   *
+   * @var \Drupal\Core\Theme\Registry
+   */
+  protected $themeRegistry;
+
+  /**
+   * Constructs a new ThemeRegistryNodeVisitor.
+   *
+   * @param \Drupal\Core\Theme\Registry $theme_registry
+   *   The theme registry.
+   */
+  public function __construct(Registry $theme_registry) {
+    $this->themeRegistry = $theme_registry;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function doEnterNode(\Twig_Node $node, \Twig_Environment $env) {
+    if ($node instanceof \Twig_Node_Module && $node->hasNode('parent')) {
+      $parent = $node->getNode('parent');
+      if ($parent && $this->expressionQualifies($parent)) {
+        $current_filename = basename($node->getAttribute('filename'));
+        $extended_filename = $parent->getAttribute('value');
+        assert('strpos($current_filename, "/") === FALSE');
+        assert('strpos($extended_filename, "/") === FALSE');
+        $path = dirname($node->getAttribute('filename'));
+        $candidates = ($current_filename === $extended_filename)
+          ? $this->getCandidateParentTemplates($current_filename, $path)
+          : $this->getCandidateTemplates($extended_filename);
+        if ($candidates === FALSE) {
+          throw new \Twig_Error(sprintf('Template "%s" extends "%s", but no such parent templates exist.', $node->getAttribute('filename'), $parent->getAttribute('value')));
+        }
+        $node->setNode('parent', $this->getReplacementNode($parent, $candidates));
+      }
+    }
+    return $node;
+  }
+
+  /**
+   * Whether the given expression qualifies for theme registry-based expansion.
+   *
+   * @param \Twig_Node $node
+   *   The Twig node to evaluate.
+   *
+   * @return bool
+   *   Whether the expression node qualifies or not.
+   */
+  protected function expressionQualifies(\Twig_Node $node) {
+    $extended_file = $node->getAttribute('value');
+    return
+      // Only override when extending a single template.
+      $node instanceof \Twig_Node_Expression_Constant
+      // Only override when the Module node is not a dynamically created one (as
+      // they are created for Embed nodes).
+      // @see \Twig_TokenParser_Embed
+      && $extended_file !== '__parent__'
+      // Only override when the extended template is pointing to a file, i.e
+      // when it doesn't include either a path or a namespace.
+      && $extended_file === basename($extended_file);
+  }
+
+  /**
+   * Replace the existing constant template with a list of templates.
+   *
+   * @param \Twig_Node_Expression_Constant $node
+   *   The Twig constant expression node to replace.
+   * @param string[] $candidates
+   *   The candidate templates that Twig should attempt to load.
+   *
+   * @return \Twig_Node_Expression_Array
+   *   The replacing Twig array expression node.
+   *
+   * @see http://twig.sensiolabs.org/doc/tags/extends.html#dynamic-inheritance
+   */
+  protected function getReplacementNode(\Twig_Node_Expression_Constant $node, array $candidates) {
+    $line = $node->getLine();
+    $replacement_node = new \Twig_Node_Expression_Array([], $line);
+    foreach ($candidates as $candidate) {
+      $replacement_node->addElement(new \Twig_Node_Expression_Constant("{$candidate['path']}/{$candidate['template']}.html.twig", $line));
+    }
+    return $replacement_node;
+  }
+
+  /**
+   * Returns candidate templates based on the theme registry.
+   *
+   * @param string $template_filename
+   *   The template file name.
+   *
+   * @return string[]
+   *   The candidate templates, including the current template.
+   */
+  protected function getCandidateTemplates($template_filename) {
+    assert('strpos($template_filename, "/") === FALSE');
+    $theme_hook = str_replace('.html.twig', '', strtr($template_filename, '-', '_'));
+    $info = $this->themeRegistry->getRuntime()->get($theme_hook);
+
+    // Put the candidates in the right order.
+    $candidates = array_reverse($info['template lineage']);
+
+    return $candidates;
+  }
+
+  /**
+   * Returns candidate parent templates based on the theme registry.
+   *
+   * @param string $template_filename
+   *   The template file name.
+   * @param string $template_path
+   *   The path relative to the Drupal root for the directory that contains this
+   *   template.
+   *
+   * @return string[]|false
+   *   The candidate parent templates, or FALSE when none exist.
+   */
+  protected function getCandidateParentTemplates($template_filename, $template_path) {
+    assert('strpos($template_filename, "/") === FALSE');
+    $candidates = $this->getCandidateTemplates($template_filename);
+
+    // The candidates include the current template too, so there must be >=2.
+    if (count($candidates) < 2) {
+      return FALSE;
+    }
+
+    // Remove the current template (and its descendants) from the candidates:
+    // only return ancestors.
+    $reversed_candidates = array_reverse($candidates);
+    for ($i = 0; $i < count($reversed_candidates); $i++) {
+      if ($reversed_candidates[$i]['path'] === $template_path) {
+        array_splice($reversed_candidates, $i);
+        break;
+      }
+    }
+    $candidates = array_reverse($reversed_candidates);
+
+    return $candidates;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function doLeaveNode(\Twig_Node $node, \Twig_Environment $env) {
+    return $node;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getPriority() {
+    // Just above the Optimizer, which is the normal last one.
+    return 256;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Template/TwigExtension.php b/core/lib/Drupal/Core/Template/TwigExtension.php
index 520a8be..f572bdd 100644
--- a/core/lib/Drupal/Core/Template/TwigExtension.php
+++ b/core/lib/Drupal/Core/Template/TwigExtension.php
@@ -12,6 +12,7 @@
 use Drupal\Core\Render\RenderableInterface;
 use Drupal\Core\Render\RendererInterface;
 use Drupal\Core\Routing\UrlGeneratorInterface;
+use Drupal\Core\Theme\Registry;
 use Drupal\Core\Theme\ThemeManagerInterface;
 use Drupal\Core\Url;
 
@@ -47,6 +48,13 @@ class TwigExtension extends \Twig_Extension {
   protected $themeManager;
 
   /**
+   * The theme registry.
+   *
+   * @var \Drupal\Core\Theme\Registry
+   */
+  protected $themeRegistry;
+
+  /**
    * The date formatter.
    *
    * @var \Drupal\Core\Datetime\DateFormatterInterface
@@ -117,6 +125,19 @@ public function setThemeManager(ThemeManagerInterface $theme_manager) {
   }
 
   /**
+   * Sets the theme registry.
+   *
+   * @param \Drupal\Core\Theme\Registry $theme_registry
+   *   The theme registry.
+   *
+   * @return $this
+   */
+  public function setThemeRegistry(Registry $theme_registry) {
+    $this->themeRegistry = $theme_registry;
+    return $this;
+  }
+
+  /**
    * Sets the date formatter.
    *
    * @param \Drupal\Core\Datetime\DateFormatter $date_formatter
@@ -192,10 +213,9 @@ public function getFilters() {
    * {@inheritdoc}
    */
   public function getNodeVisitors() {
-    // The node visitor is needed to wrap all variables with
-    // render_var -> TwigExtension->renderVar() function.
     return [
       new TwigNodeVisitor(),
+      new ThemeRegistryNodeVisitor($this->themeRegistry),
     ];
   }
 
diff --git a/core/lib/Drupal/Core/Theme/Registry.php b/core/lib/Drupal/Core/Theme/Registry.php
index a0af702..4417615 100644
--- a/core/lib/Drupal/Core/Theme/Registry.php
+++ b/core/lib/Drupal/Core/Theme/Registry.php
@@ -510,6 +510,20 @@ protected function processExtension(array &$cache, $name, $type, $theme, $path)
           $result[$hook]['path'] = $path . '/templates';
         }
 
+        if (isset($cache[$hook]['template lineage'])) {
+          $result[$hook]['template lineage'] = $cache[$hook]['template lineage'];
+        }
+        else {
+          $result[$hook]['template lineage'] = array();
+        }
+        if (isset($result[$hook]['template'])) {
+          $result[$hook]['template lineage'][] = array(
+            'extension' => $theme,
+            'template' => $result[$hook]['template'],
+            'path' => $result[$hook]['path'],
+          );
+        }
+
         // If the default keys are not set, use the default values registered
         // by the module.
         if (isset($cache[$hook])) {
diff --git a/core/modules/system/src/SystemConfigSubscriber.php b/core/modules/system/src/SystemConfigSubscriber.php
index ddd37be..d9a2e55 100644
--- a/core/modules/system/src/SystemConfigSubscriber.php
+++ b/core/modules/system/src/SystemConfigSubscriber.php
@@ -5,6 +5,7 @@
 use Drupal\Core\Config\ConfigCrudEvent;
 use Drupal\Core\Config\ConfigEvents;
 use Drupal\Core\Config\ConfigImporterEvent;
+use Drupal\Core\PhpStorage\PhpStorageFactory;
 use Drupal\Core\Routing\RouteBuilderInterface;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
@@ -41,6 +42,10 @@ public function onConfigSave(ConfigCrudEvent $event) {
     $saved_config = $event->getConfig();
     if ($saved_config->getName() == 'system.theme' && ($event->isChanged('admin') || $event->isChanged('default'))) {
       $this->routerBuilder->setRebuildNeeded();
+      // Wipe the Twig PHP Storage cache, to ensure templates that extend or
+      // include another template use the correct list of candidate templates.
+      // @see \Drupal\Core\Template\ThemeRegistryNodeVisitor
+      PhpStorageFactory::get('twig')->deleteAll();
     }
   }
 
diff --git a/core/modules/system/tests/modules/twig_extension_test/twig_extension_test.services.yml b/core/modules/system/tests/modules/twig_extension_test/twig_extension_test.services.yml
index 491d1e8..dea3cac 100644
--- a/core/modules/system/tests/modules/twig_extension_test/twig_extension_test.services.yml
+++ b/core/modules/system/tests/modules/twig_extension_test/twig_extension_test.services.yml
@@ -2,5 +2,7 @@ services:
   twig_extension_test.twig.test_extension:
     arguments: ['@renderer']
     class: Drupal\twig_extension_test\TwigExtension\TestExtension
+    calls:
+      - [setThemeRegistry, ['@theme.registry']]
     tags:
       - { name: twig.extension }
diff --git a/core/modules/system/tests/modules/twig_theme_test/templates/twig-registry-loader-test-extend-same-name.html.twig b/core/modules/system/tests/modules/twig_theme_test/templates/twig-registry-loader-test-extend-same-name.html.twig
new file mode 100644
index 0000000..8883d27
--- /dev/null
+++ b/core/modules/system/tests/modules/twig_theme_test/templates/twig-registry-loader-test-extend-same-name.html.twig
@@ -0,0 +1,2 @@
+{% set attributes = attributes.addClass('module') %}
+<test-extend-same-name{{ attributes }}>
diff --git a/core/modules/system/tests/modules/twig_theme_test/templates/twig-registry-loader-test.html.twig b/core/modules/system/tests/modules/twig_theme_test/templates/twig-registry-loader-test.html.twig
index a3723b5..48c29a4 100644
--- a/core/modules/system/tests/modules/twig_theme_test/templates/twig-registry-loader-test.html.twig
+++ b/core/modules/system/tests/modules/twig_theme_test/templates/twig-registry-loader-test.html.twig
@@ -1,5 +1,6 @@
 {% extends "twig-registry-loader-test-extend.html.twig" %}
 
 {% block content %}
+  {% include "twig-registry-loader-test-extend-same-name.html.twig" %}
   {% include "twig-registry-loader-test-include.html.twig" %}
 {% endblock %}
diff --git a/core/modules/system/tests/modules/twig_theme_test/twig_theme_test.module b/core/modules/system/tests/modules/twig_theme_test/twig_theme_test.module
index a8b4086..9ffc94b 100644
--- a/core/modules/system/tests/modules/twig_theme_test/twig_theme_test.module
+++ b/core/modules/system/tests/modules/twig_theme_test/twig_theme_test.module
@@ -37,6 +37,9 @@ function twig_theme_test_theme($existing, $type, $theme, $path) {
   $items['twig_registry_loader_test_extend'] = [
     'variables' => [],
   ];
+  $items['twig_registry_loader_test_extend_same_name'] = [
+    'variables' => [],
+  ];
   $items['twig_raw_test'] = [
     'variables' => ['script' => ''],
   ];
diff --git a/core/modules/system/tests/src/Functional/Theme/TwigExtensionTest.php b/core/modules/system/tests/src/Functional/Theme/TwigExtensionTest.php
index f2491ac..8073260 100644
--- a/core/modules/system/tests/src/Functional/Theme/TwigExtensionTest.php
+++ b/core/modules/system/tests/src/Functional/Theme/TwigExtensionTest.php
@@ -49,7 +49,7 @@ function testTwigExtensionFilter() {
   /**
    * Tests that the Twig extension's function produces expected output.
    */
-  function testTwigExtensionFunction() {
+  function testsTwigExtensionFunction() {
     $this->config('system.theme')
       ->set('default', 'test_theme')
       ->save();
diff --git a/core/modules/system/tests/src/Functional/Theme/TwigRegistryLoaderTest.php b/core/modules/system/tests/src/Functional/Theme/TwigRegistryLoaderTest.php
index 2446289..012bd85 100644
--- a/core/modules/system/tests/src/Functional/Theme/TwigRegistryLoaderTest.php
+++ b/core/modules/system/tests/src/Functional/Theme/TwigRegistryLoaderTest.php
@@ -23,6 +23,9 @@ class TwigRegistryLoaderTest extends BrowserTestBase {
    */
   protected $twig;
 
+  /**
+   * {@inheritdoc}
+   */
   protected function setUp() {
     parent::setUp();
     \Drupal::service('theme_handler')->install(['test_theme_twig_registry_loader', 'test_theme_twig_registry_loader_theme', 'test_theme_twig_registry_loader_subtheme']);
@@ -46,20 +49,22 @@ public function testTemplateDiscovery() {
   /**
    * Tests template extension and includes using the Drupal theme registry.
    */
-  public function testTwigNamespaces() {
+  public function testExtendsAndInclude() {
     // Test the module-provided extend and insert templates.
     $this->drupalGet('twig-theme-test/registry-loader');
     $this->assertText('This line is from twig_theme_test/templates/twig-registry-loader-test-extend.html.twig');
     $this->assertText('This line is from twig_theme_test/templates/twig-registry-loader-test-include.html.twig');
+    $this->assertRaw('<test-extend-same-name class="module">');
 
     // Enable a theme that overrides the extend and insert templates to ensure
-    // they are picked up by the registry loader.
+    // they are picked up by the registry node visitor.
     $this->config('system.theme')
       ->set('default', 'test_theme_twig_registry_loader')
       ->save();
     $this->drupalGet('twig-theme-test/registry-loader');
     $this->assertText('This line is from test_theme_twig_registry_loader/templates/twig-registry-loader-test-extend.html.twig');
     $this->assertText('This line is from test_theme_twig_registry_loader/templates/twig-registry-loader-test-include.html.twig');
+    $this->assertRaw('<test-extend-same-name class="theme-test_theme_twig_registry_loader module">');
 
     // Enable overriding theme that overrides the extend and insert templates
     // from the base theme.
@@ -69,6 +74,7 @@ public function testTwigNamespaces() {
     $this->drupalGet('twig-theme-test/registry-loader');
     $this->assertText('This line is from test_theme_twig_registry_loader_theme/templates/twig-registry-loader-test-extend.html.twig');
     $this->assertText('This line is from test_theme_twig_registry_loader_theme/templates/twig-registry-loader-test-include.html.twig');
+    $this->assertRaw('<test-extend-same-name class="theme-test_theme_twig_registry_loader_theme theme-test_theme_twig_registry_loader module">');
 
     // Enable a subtheme for the theme that doesn't have any overrides to make
     // sure that templates are being loaded from the first parent which has the
@@ -79,6 +85,7 @@ public function testTwigNamespaces() {
     $this->drupalGet('twig-theme-test/registry-loader');
     $this->assertText('This line is from test_theme_twig_registry_loader_theme/templates/twig-registry-loader-test-extend.html.twig');
     $this->assertText('This line is from test_theme_twig_registry_loader_theme/templates/twig-registry-loader-test-include.html.twig');
+    $this->assertRaw('<test-extend-same-name class="theme-test_theme_twig_registry_loader_theme theme-test_theme_twig_registry_loader module">');
   }
 
 }
diff --git a/core/modules/system/tests/themes/test_theme_twig_registry_loader/templates/twig-registry-loader-test-extend-same-name.html.twig b/core/modules/system/tests/themes/test_theme_twig_registry_loader/templates/twig-registry-loader-test-extend-same-name.html.twig
new file mode 100644
index 0000000..97eda90
--- /dev/null
+++ b/core/modules/system/tests/themes/test_theme_twig_registry_loader/templates/twig-registry-loader-test-extend-same-name.html.twig
@@ -0,0 +1,2 @@
+{% extends "twig-registry-loader-test-extend-same-name.html.twig" %}
+{% set attributes = attributes.addClass('theme-test_theme_twig_registry_loader') %}
diff --git a/core/modules/system/tests/themes/test_theme_twig_registry_loader_theme/templates/twig-registry-loader-test-extend-same-name.html.twig b/core/modules/system/tests/themes/test_theme_twig_registry_loader_theme/templates/twig-registry-loader-test-extend-same-name.html.twig
new file mode 100644
index 0000000..2dd645e
--- /dev/null
+++ b/core/modules/system/tests/themes/test_theme_twig_registry_loader_theme/templates/twig-registry-loader-test-extend-same-name.html.twig
@@ -0,0 +1,2 @@
+{% extends "twig-registry-loader-test-extend-same-name.html.twig" %}
+{% set attributes = attributes.addClass('theme-test_theme_twig_registry_loader_theme') %}
diff --git a/core/tests/Drupal/Tests/Core/Template/TwigExtensionTest.php b/core/tests/Drupal/Tests/Core/Template/TwigExtensionTest.php
index c4805bc..5f4e71d 100644
--- a/core/tests/Drupal/Tests/Core/Template/TwigExtensionTest.php
+++ b/core/tests/Drupal/Tests/Core/Template/TwigExtensionTest.php
@@ -8,6 +8,7 @@
 use Drupal\Core\Template\Loader\StringLoader;
 use Drupal\Core\Template\TwigEnvironment;
 use Drupal\Core\Template\TwigExtension;
+use Drupal\Core\Theme\Registry;
 use Drupal\Core\Url;
 use Drupal\Tests\UnitTestCase;
 
@@ -65,8 +66,9 @@ public function setUp() {
     $this->urlGenerator = $this->getMock('\Drupal\Core\Routing\UrlGeneratorInterface');
     $this->themeManager = $this->getMock('\Drupal\Core\Theme\ThemeManagerInterface');
     $this->dateFormatter = $this->getMock('\Drupal\Core\Datetime\DateFormatterInterface');
+    $registry = $this->prophesize(Registry::class);
 
-    $this->systemUnderTest = new TwigExtension($this->renderer, $this->urlGenerator, $this->themeManager, $this->dateFormatter);
+    $this->systemUnderTest = (new TwigExtension($this->renderer, $this->urlGenerator, $this->themeManager, $this->dateFormatter))->setThemeRegistry($registry->reveal());
   }
 
   /**
diff --git a/core/themes/bartik/templates/block--search-form-block.html.twig b/core/themes/bartik/templates/block--search-form-block.html.twig
index b2af1ed..df24e95 100644
--- a/core/themes/bartik/templates/block--search-form-block.html.twig
+++ b/core/themes/bartik/templates/block--search-form-block.html.twig
@@ -1,4 +1,4 @@
-{% extends "@classy/block/block--search-form-block.html.twig" %}
+{% extends "block--search-form-block.html.twig" %}
 {#
 /**
  * @file
diff --git a/core/themes/bartik/templates/block--system-menu-block.html.twig b/core/themes/bartik/templates/block--system-menu-block.html.twig
index d22cfbf..c065cf2 100644
--- a/core/themes/bartik/templates/block--system-menu-block.html.twig
+++ b/core/themes/bartik/templates/block--system-menu-block.html.twig
@@ -1,4 +1,4 @@
-{% extends "@classy/block/block--system-menu-block.html.twig" %}
+{% extends "block--system-menu-block.html.twig" %}
 {#
 /**
  * @file
diff --git a/core/themes/bartik/templates/page-title.html.twig b/core/themes/bartik/templates/page-title.html.twig
index e061cd2..f728998 100644
--- a/core/themes/bartik/templates/page-title.html.twig
+++ b/core/themes/bartik/templates/page-title.html.twig
@@ -1,4 +1,4 @@
-{% extends "@classy/content/page-title.html.twig" %}
+{% extends "page-title.html.twig" %}
 {#
 /**
  * @file
diff --git a/core/themes/bartik/templates/status-messages.html.twig b/core/themes/bartik/templates/status-messages.html.twig
index a4e1e9e..b9539e2 100644
--- a/core/themes/bartik/templates/status-messages.html.twig
+++ b/core/themes/bartik/templates/status-messages.html.twig
@@ -1,4 +1,4 @@
-{% extends "@classy/misc/status-messages.html.twig" %}
+{% extends "status-messages.html.twig" %}
 {#
 /**
  * @file
diff --git a/core/themes/seven/templates/block--local-actions-block.html.twig b/core/themes/seven/templates/block--local-actions-block.html.twig
index 6539758..d960201 100644
--- a/core/themes/seven/templates/block--local-actions-block.html.twig
+++ b/core/themes/seven/templates/block--local-actions-block.html.twig
@@ -1,4 +1,4 @@
-{% extends "@block/block.html.twig" %}
+{% extends "block.html.twig" %}
 {#
 /**
  * @file
