diff --git a/core/modules/responsive_image/responsive_image.module b/core/modules/responsive_image/responsive_image.module
index 08545cc..494ed82 100644
--- a/core/modules/responsive_image/responsive_image.module
+++ b/core/modules/responsive_image/responsive_image.module
@@ -77,88 +77,28 @@ function responsive_image_theme() {
   return array(
     'responsive_image' => array(
       'variables' => array(
+        'link_path' => NULL,
         'uri' => NULL,
-        'width' => NULL,
-        'height' => NULL,
-        'alt' => '',
-        'title' => NULL,
         'attributes' => array(),
         'responsive_image_style_id' => array(),
       ),
     ),
-    'responsive_image_formatter' => array(
-      'variables' => array(
-        'item' => NULL,
-        'url' => NULL,
-        'responsive_image_style_id' => array(),
-      ),
-      'function' => 'theme_responsive_image_formatter',
-    ),
   );
 }
 
 /**
- * Returns HTML for a responsive image field formatter.
- *
- * @param array $variables
- *   An associative array containing:
- *   - item: An ImageItem object.
- *   - responsive_image_style_id: The ID of the responsive image style.
- *   - url: An optional \Drupal\Core\Url object.
- *
- * @ingroup themeable
- */
-function theme_responsive_image_formatter($variables) {
-  $item = $variables['item'];
-  if (!isset($variables['responsive_image_style_id']) || empty($variables['responsive_image_style_id'])) {
-    $image_formatter = array(
-      '#theme' => 'image_formatter',
-      '#item' => $item,
-      '#url' => $variables['url'],
-    );
-    return drupal_render($image_formatter);
-  }
-
-  $responsive_image = array(
-    '#theme' => 'responsive_image',
-    '#width' => $item->width,
-    '#height' => $item->height,
-    '#responsive_image_style_id' => $variables['responsive_image_style_id'],
-  );
-  if (isset($item->uri)) {
-    $responsive_image['#uri'] = $item->uri;
-  }
-  elseif ($entity = $item->entity) {
-    $responsive_image['#uri'] = $entity->getFileUri();
-    $responsive_image['#entity'] = $entity;
-  }
-  $responsive_image['#alt'] = $item->alt;
-  if (Unicode::strlen($item->title) != 0) {
-    $responsive_image['#title'] = $item->title;
-  }
-  if (isset($variables['url'])) {
-    return \Drupal::l($responsive_image, $variables['url']);
-  }
-
-  return drupal_render($responsive_image);
-}
-
-/**
  * Prepares variables for a responsive image.
  *
  * Default template: responsive-image.html.twig.
  *
  * @param $variables
  *   An associative array containing:
- *   - uri: Either the path of the image file (relative to base_path()) or a
- *     full URL.
+ *   - uri: The URI of the image.
  *   - width: The width of the image (if known).
  *   - height: The height of the image (if known).
- *   - alt: The alternative text for text-based browsers.
- *   - title: The title text is displayed when the image is hovered in some
- *     popular browsers.
  *   - attributes: Associative array of attributes to be placed in the img tag.
  *   - responsive_image_style_id: The ID of the responsive image style.
+ *   - link_path: The path to link the image to (optional).
  */
 function template_preprocess_responsive_image(&$variables) {
   // Make sure that width and height are proper values
@@ -194,11 +134,16 @@ function template_preprocess_responsive_image(&$variables) {
       ),
     ),
   );
-  foreach (array('alt', 'title', 'attributes') as $key) {
-    if (isset($variables[$key])) {
-      $variables['img_element']["#$key"] = $variables[$key];
-      unset($variables[$key]);
+  if (isset($variables['attributes'])) {
+    if (isset($variables['attributes']['alt'])) {
+      $variables['img_element']['#alt'] = $variables['attributes']['alt'];
+      unset($variables['attributes']['alt']);
+    }
+    if (isset($variables['attributes']['title'])) {
+      $variables['img_element']['#title'] = $variables['attributes']['title'];
+      unset($variables['attributes']['title']);
     }
+    $variables['img_element']['#attributes'] = $variables['attributes'];
   }
 }
 
diff --git a/core/modules/responsive_image/src/Element/ResponsiveImage.php b/core/modules/responsive_image/src/Element/ResponsiveImage.php
new file mode 100644
index 0000000..9da04f9
--- /dev/null
+++ b/core/modules/responsive_image/src/Element/ResponsiveImage.php
@@ -0,0 +1,30 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\responsive_image\Element\ResponsiveImage.
+ */
+
+namespace Drupal\responsive_image\Element;
+
+use Drupal\Core\Render\Element\RenderElement;
+
+/**
+ * Provides a responsive image element.
+ *
+ * @RenderElement("responsive_image")
+ */
+class ResponsiveImage extends RenderElement {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getInfo() {
+    return [
+      '#theme' => 'responsive_image',
+      '#attached' => [
+        'library' => ['core/picturefill'],
+      ],
+    ];
+  }
+
+}
diff --git a/core/modules/responsive_image/src/Plugin/Field/FieldFormatter/ResponsiveImageFormatter.php b/core/modules/responsive_image/src/Plugin/Field/FieldFormatter/ResponsiveImageFormatter.php
index 3db169e..d82ed5c 100644
--- a/core/modules/responsive_image/src/Plugin/Field/FieldFormatter/ResponsiveImageFormatter.php
+++ b/core/modules/responsive_image/src/Plugin/Field/FieldFormatter/ResponsiveImageFormatter.php
@@ -15,6 +15,7 @@
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Url;
 use Drupal\image\Plugin\Field\FieldFormatter\ImageFormatterBase;
+use Drupal\Component\Utility\Unicode;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -205,21 +206,32 @@ public function viewElements(FieldItemListInterface $items) {
         $url = Url::fromUri(file_create_url($file->getFileUri()));
       }
       $elements[$delta] = array(
-        '#theme' => 'responsive_image_formatter',
-        '#attached' => array(
-          'library' => array(
-            'core/picturefill',
-          ),
-        ),
-        '#item' => $file->_referringItem,
+        '#type' => 'responsive_image',
         '#responsive_image_style_id' => $responsive_image_style ? $responsive_image_style->id() : '',
-        '#url' => $url,
+        '#link_path' => $url,
+        '#uri' => $file->getFileUri(),
         '#cache' => array(
           'tags' => $cache_tags,
         ),
       );
-    }
+      // Get the image dimensions.
+      $image = \Drupal::service('image.factory')->get($elements[$delta]['#uri']);
 
+      if ($image->isValid()) {
+        $elements[$delta]['#width'] = $image->getWidth();
+        $elements[$delta]['#height'] = $image->getHeight();
+      }
+      else {
+        $elements[$delta]['#width'] = $elements[$delta]['#height'] = NULL;
+      }
+      $item = $items[$delta]->getValue();
+      if (isset($item['alt']) && Unicode::strlen($item['alt']) != 0) {
+        $elements[$delta]['#attributes']['alt'] = $item['alt'];
+      }
+      if (isset($item['title']) && Unicode::strlen($item['title']) != 0) {
+        $elements[$delta]['#attributes']['title'] = $item['title'];
+      }
+    }
     return $elements;
   }
 }
diff --git a/core/modules/responsive_image/src/Tests/ResponsiveImageFieldDisplayTest.php b/core/modules/responsive_image/src/Tests/ResponsiveImageFieldDisplayTest.php
index 2a84bc0..b07a8de 100644
--- a/core/modules/responsive_image/src/Tests/ResponsiveImageFieldDisplayTest.php
+++ b/core/modules/responsive_image/src/Tests/ResponsiveImageFieldDisplayTest.php
@@ -193,25 +193,22 @@ protected function doTestResponsiveImageFieldFormatters($scheme, $empty_styles =
     $display_options = array(
       'type' => 'responsive_image',
       'settings' => array(
-        'image_link' => 'file'
+        'image_link' => 'file',
+        'responsive_image_style' => 'style_one',
       ),
     );
     $display = entity_get_display('node', 'article', 'default');
     $display->setComponent($field_name, $display_options)
       ->save();
 
-    $image = array(
-      '#theme' => 'image',
-      '#uri' => $image_uri,
-      '#width' => 360,
-      '#height' => 240,
-      '#alt' => $alt,
-    );
-    $default_output = '<a href="' . file_create_url($image_uri) . '">' . drupal_render($image) . '</a>';
+    $default_output = '<a href="' . file_create_url($image_uri) . '"><picture';
     $this->drupalGet('node/' . $nid);
     $cache_tags_header = $this->drupalGetHeader('X-Drupal-Cache-Tags');
     $this->assertTrue(!preg_match('/ image_style\:/', $cache_tags_header), 'No image style cache tag found.');
 
+    // The Responsive Image module outputs a newline after the <a> tag, remove
+    // it so it's easier to test the output.
+    $this->removeWhiteSpace();
     $this->assertRaw($default_output, 'Image linked to file formatter displaying correctly on full node view.');
     // Verify that the image can be downloaded.
     $this->assertEqual(file_get_contents($test_image->uri), $this->drupalGet(file_create_url($image_uri)), 'File was downloaded successfully.');
@@ -416,6 +413,9 @@ private function assertResponsiveImageFieldFormattersLink($link_type) {
 
     // Output should contain all image styles and all breakpoints.
     $this->drupalGet('node/' . $nid);
+    // The Responsive Image module outputs a newline after the <a> tag, remove
+    // it so it's easier to test the output.
+    $this->removeWhiteSpace();
     switch ($link_type) {
       case 'file':
         // Make sure the link to the file is present.
diff --git a/core/modules/responsive_image/templates/responsive-image.html.twig b/core/modules/responsive_image/templates/responsive-image.html.twig
index 9a89043..eb96f9a 100644
--- a/core/modules/responsive_image/templates/responsive-image.html.twig
+++ b/core/modules/responsive_image/templates/responsive-image.html.twig
@@ -5,7 +5,8 @@
  *
  * Available variables:
  * - sources: The attributes of the <source> tags for this <picture> tag.
- * - fallback_image: The fallback <img> tag to use for this <picture> tag.
+ * - img_element: The controlling image, with the fallback image in srcset.
+ * - link_path: An optional URL the image can be linked to.
  *
  * @see template_preprocess()
  * @see template_preprocess_responsive_image()
@@ -13,6 +14,9 @@
  * @ingroup themeable
  */
 #}
+{% if link_path %}
+<a href="{{ link_path }}">
+{% endif %}
 <picture>
   {% if sources %}
     {#
@@ -28,3 +32,6 @@
   {# The controlling image, with the fallback image in srcset. #}
   {{ img_element }}
 </picture>
+{% if link_path %}
+</a>
+{% endif %}
