diff --git a/core/modules/overlay/overlay.module b/core/modules/overlay/overlay.module
index cc29255..0c3b6ed 100644
--- a/core/modules/overlay/overlay.module
+++ b/core/modules/overlay/overlay.module
@@ -183,7 +183,9 @@ function overlay_init() {
  * the supplemental regions of the overlay on the next page request.
  */
 function overlay_exit() {
-  // Check that we are in an overlay child page.
+  // Check that we are in an overlay child page. Note that this should never
+  // return TRUE on a cached page view, since the child mode is not set until
+  // overlay_init() is called.
   if (overlay_get_mode() == 'child') {
     // Load any markup that was stored earlier in the page request, via calls
     // to overlay_store_rendered_content(). If none was stored, this is not a
@@ -438,44 +440,6 @@ function overlay_disable_message() {
 }
 
 /**
- * Returns the HTML for the message about how to disable the overlay.
- *
- * @param $variables
- *   An associative array with an 'element' element, which itself is an
- *   associative array containing:
- *   - profile_link: The link to this user's account.
- *   - dismiss_message_link: The link to dismiss the overlay.
- *
- * @ingroup themeable
- */
-function theme_overlay_disable_message($variables) {
-  $element = $variables['element'];
-
-  // Add CSS classes to hide the links from most sighted users, while keeping
-  // them accessible to screen-reader users and keyboard-only users. To assist
-  // screen-reader users, this message appears in both the parent and child
-  // documents, but only the one in the child document is part of the tab order.
-  foreach (array('profile_link', 'dismiss_message_link') as $key) {
-    $element[$key]['#options']['attributes']['class'][] = 'element-invisible';
-    if (overlay_get_mode() == 'child') {
-      $element[$key]['#options']['attributes']['class'][] = 'element-focusable';
-    }
-  }
-
-  // Render the links.
-  $output = drupal_render($element['profile_link']) . ' ' . drupal_render($element['dismiss_message_link']);
-
-  // Add a heading for screen-reader users. The heading doesn't need to be seen
-  // by sighted users.
-  $output = '<h3 class="element-invisible">' . t('Options for the administrative overlay') . '</h3>' . $output;
-
-  // Wrap in a container for styling.
-  $output = '<div id="overlay-disable-message" class="clearfix">' . $output . '</div>';
-
-  return $output;
-}
-
-/**
  * Implements hook_block_access().
  */
 function overlay_block_access($block) {
@@ -546,6 +510,36 @@ function template_preprocess_overlay(&$variables) {
 }
 
 /**
+ * Preprocess variables for the message about how to disable the overlay.
+ *
+ * @param $variables
+ *   An associative array with an 'element' element, which itself is an
+ *   associative array containing:
+ *   - profile_link: The link to this user's account.
+ *   - dismiss_message_link: The link to dismiss the overlay.
+ *
+ * @ingroup themeable
+ */
+function template_preprocess_overlay_disable_message(&$variables) {
+  $element = $variables['element'];
+
+  // Add CSS classes to hide the links from most sighted users, while keeping
+  // them accessible to screen-reader users and keyboard-only users. To assist
+  // screen-reader users, this message appears in both the parent and child
+  // documents, but only the one in the child document is part of the tab order.
+  foreach (array('profile_link', 'dismiss_message_link') as $key) {
+    $element[$key]['#options']['attributes']['class'][] = 'element-invisible';
+    if (overlay_get_mode() == 'child') {
+      $element[$key]['#options']['attributes']['class'][] = 'element-focusable';
+    }
+  }
+
+  // Render the links.
+  $variables['profile_link'] = $element['profile_link'];
+  $variables['dismiss_link'] = $element['dismiss_message_link'];
+}
+
+/**
  * Implements template_process_HOOK() for overlay.tpl.php
  *
  * Places the rendered HTML for the page body into a top level variable.
diff --git a/core/modules/overlay/templates/overlay-disable-message.html.twig b/core/modules/overlay/templates/overlay-disable-message.html.twig
new file mode 100644
index 0000000..4b9c38a
--- /dev/null
+++ b/core/modules/overlay/templates/overlay-disable-message.html.twig
@@ -0,0 +1,20 @@
+{#
+/**
+ * @file
+ * Default theme implementation for the message about how to disable the overlay.
+ *
+ * Available variables:
+ * - attributes: An array of element attributes.
+ * - profile_link: Rendered link.
+ * - dismiss_link: Rendered link to disable the message.
+ *
+ * @see template_preprocess()
+ * @see template_preprocess_overlay_disable_message()
+ *
+ * @ingroup themeable
+ */
+#}
+<div id="overlay-disable-message" class="clearfix">
+  <h3 class="element-invisible">{{ "Options for the administrative overlay"|t }}</h3>
+  {{ profile_link }} {{ dismiss_link }}
+</div>
diff --git a/core/modules/overlay/templates/overlay.html.twig b/core/modules/overlay/templates/overlay.html.twig
new file mode 100644
index 0000000..e86ecd6
--- /dev/null
+++ b/core/modules/overlay/templates/overlay.html.twig
@@ -0,0 +1,34 @@
+{#
+/**
+ * @file
+ * Default theme implementation to display a page in the overlay.
+ *
+ * Available variables:
+ * - title: the (sanitized) title of the page.
+ * - page: The rendered page content.
+ * - tabs: Tabs linking to any sub-pages beneath the current page (e.g., the view
+ * and edit tabs when displaying a node).
+ *
+ * @see template_preprocess()
+ * @see template_preprocess_overlay()
+ *
+ * @ingroup themeable
+ */
+#}
+{{ disable_overlay }}
+<div id="overlay"{{ attributes }}>
+  <div id="overlay-titlebar" class="clearfix">
+    <div id="overlay-title-wrapper" class="clearfix">
+      <h1 id="overlay-title"{{ title_attributes }}>{{ title }}</h1>
+    </div>
+    <div id="overlay-close-wrapper">
+      <a id="overlay-close" href="#" class="overlay-close"><span class="element-invisible">{{ 'Close overlay'|t }}</span></a>
+    </div>
+    {% if tabs %}
+      <h2 class="element-invisible">{{ 'Primary tabs'|t }}</h2><ul id="overlay-tabs">{{ render_var(tabs) }}</ul>
+    {% endif %}
+  </div>
+  <div id="overlay-content"{{ content_attributes }}>
+    {{ page }}
+  </div>
+</div>
diff --git a/core/modules/overlay/templates/overlay.tpl.php b/core/modules/overlay/templates/overlay.tpl.php
deleted file mode 100644
index 38e6664..0000000
--- a/core/modules/overlay/templates/overlay.tpl.php
+++ /dev/null
@@ -1,38 +0,0 @@
-<?php
-
-/**
- * @file
- * Default theme implementation to display a page in the overlay.
- *
- * Available variables:
- * - $title: the (sanitized) title of the page.
- * - $page: The rendered page content.
- * - $tabs (array): Tabs linking to any sub-pages beneath the current page
- *   (e.g., the view and edit tabs when displaying a node).
- * Helper variables:
- * - $classes_array: Array of HMTL class attribute values. It is flattened into
- *   a string within the variable $classes.
- *
- * @see template_preprocess()
- * @see template_preprocess_overlay()
- * @see template_process()
- *
- * @ingroup themeable
- */
-?>
-
-<?php print render($disable_overlay); ?>
-<div id="overlay" <?php print $attributes; ?>>
-  <div id="overlay-titlebar" class="clearfix">
-    <div id="overlay-title-wrapper" class="clearfix">
-      <h1 id="overlay-title"<?php print $title_attributes; ?>><?php print $title; ?></h1>
-    </div>
-    <div id="overlay-close-wrapper">
-      <a id="overlay-close" href="#" class="overlay-close"><span class="element-invisible"><?php print t('Close overlay'); ?></span></a>
-    </div>
-    <?php if ($tabs): ?><h2 class="element-invisible"><?php print t('Primary tabs'); ?></h2><ul id="overlay-tabs"><?php print render($tabs); ?></ul><?php endif; ?>
-  </div>
-  <div id="overlay-content"<?php print $content_attributes; ?>>
-    <?php print $page; ?>
-  </div>
-</div>
