diff --git a/core/modules/aggregator/aggregator.module b/core/modules/aggregator/aggregator.module
index bf17629..ee183e4 100644
--- a/core/modules/aggregator/aggregator.module
+++ b/core/modules/aggregator/aggregator.module
@@ -50,27 +50,17 @@ function aggregator_help($path, $arg) {
  */
 function aggregator_theme() {
   return array(
-    'aggregator_feed_source' => array(
-      'variables' => array('aggregator_feed' => NULL, 'view_mode' => NULL),
+    'aggregator_feed' => array(
+      'render element' => 'elements',
       'file' => 'aggregator.pages.inc',
-      'template' => 'aggregator-feed-source',
+      'template' => 'aggregator-feed',
     ),
     'aggregator_block_item' => array(
       'variables' => array('item' => NULL, 'feed' => 0),
       'template' => 'aggregator-block-item',
     ),
-    'aggregator_summary_items' => array(
-      'variables' => array('summary_items' => NULL, 'source' => NULL),
-      'file' => 'aggregator.pages.inc',
-      'template' => 'aggregator-summary-items',
-    ),
-    'aggregator_summary_item' => array(
-      'variables' => array('aggregator_item' => NULL, 'view_mode' => NULL),
-      'file' => 'aggregator.pages.inc',
-      'template' => 'aggregator-summary-item',
-    ),
     'aggregator_item' => array(
-      'variables' => array('aggregator_item' => NULL, 'view_mode' => NULL),
+      'render element' => 'elements',
       'file' => 'aggregator.pages.inc',
       'template' => 'aggregator-item',
     ),
@@ -142,6 +132,101 @@ function aggregator_permission() {
 }
 
 /**
+ * Implements hook_entity_bundle_info().
+ */
+function aggregator_entity_bundle_info() {
+  $bundles['aggregator_feed']['aggregator_feed']['label'] = t('Aggregator feed');
+  $bundles['aggregator_item']['aggregator_item']['label'] = t('Aggregator item');
+  return $bundles;
+}
+
+/**
+ * Implements hook_field_extra_fields().
+ */
+function aggregator_field_extra_fields() {
+  $extra = array();
+
+  $extra['aggregator_feed']['aggregator_feed'] = array(
+    'form' => array(
+      'title' => array(
+        'label' => t('Title'),
+        'description' => t('Title'),
+        'weight' => -1,
+      ),
+      'url' => array(
+        'label' => t('URL'),
+        'description' => t('URL'),
+        'weight' => 0,
+      ),
+      'refresh' => array(
+        'label' => t('Update interval'),
+        'description' => t('Update interval'),
+        'weight' => 0,
+      ),
+    ),
+    'display' => array(
+      'items' => array(
+        'label' => t('Items'),
+        'description' => t('Items associated with this feed'),
+        'weight' => 0,
+      ),
+      'link' => array(
+        'label' => t('Link'),
+        'description' => t("The link to this feed's website"),
+        'weight' => 0,
+      ),
+      'checked' => array(
+        'label' => t('Last checked'),
+        'description' => t('When this feed was last checked'),
+        'weight' => 0,
+      ),
+      'description' => array(
+        'label' => t('Description'),
+        'description' => t('The description of this feed'),
+        'weight' => 0,
+      ),
+      'image' => array(
+        'label' => t('Image'),
+        'description' => t('The feed image'),
+        'weight' => 0,
+      ),
+    ),
+  );
+
+  $extra['aggregator_item']['aggregator_item'] = array(
+    'display' => array(
+      'feed' => array(
+        'label' => t('Source feed'),
+        'description' => t('The aggregator feed entity associated with this item'),
+        'weight' => 0,
+      ),
+      'link' => array(
+        'label' => t('Link'),
+        'description' => t("The link to this feed item"),
+        'weight' => 0,
+      ),
+      'author' => array(
+        'label' => t('Author'),
+        'description' => t('Author of this feed item'),
+        'weight' => 0,
+      ),
+      'description' => array(
+        'label' => t('Description'),
+        'description' => t('The description of this feed item'),
+        'weight' => 0,
+      ),
+      'timestamp' => array(
+        'label' => t('Date'),
+        'description' => t('Posted date of the feed as time ago'),
+        'weight' => 0,
+      ),
+    ),
+  );
+
+  return $extra;
+}
+
+/**
  * Implements hook_cron().
  *
  * Queues news feeds for updates once their refresh interval has elapsed.
diff --git a/core/modules/aggregator/aggregator.pages.inc b/core/modules/aggregator/aggregator.pages.inc
index 75e4997..df468e3 100644
--- a/core/modules/aggregator/aggregator.pages.inc
+++ b/core/modules/aggregator/aggregator.pages.inc
@@ -6,6 +6,7 @@
  */
 
 use Drupal\aggregator\Entity\Feed;
+use Drupal\Component\Utility\String;
 use Drupal\Core\Entity\EntityInterface;
 
 /**
@@ -48,30 +49,22 @@ function aggregator_load_feed_items($type, $data = NULL, $limit = 20) {
  *
  * @param array $variables
  *   An associative array containing:
- *   - aggregator_item: An individual feed item for display on the aggregator
- *     page.
+ *   - elements: An array of elements to display in view mode.
  */
 function template_preprocess_aggregator_item(&$variables) {
-  $item = $variables['aggregator_item'];
-
-  $variables['feed_url'] = check_url($item->getLink());
-  $variables['feed_title'] = check_plain($item->getTitle());
-  $variables['content'] = aggregator_filter_xss($item->getDescription());
-
-  $variables['source_url'] = '';
-  $variables['source_title'] = '';
-  $fid = $item->getFeedId();
-  if (isset($item->ftitle) && $fid !== NULL) {
-    $variables['source_url'] = url('aggregator/sources/' . $fid);
-    $variables['source_title'] = check_plain($item->ftitle);
-  }
-  if (date('Ymd', $item->getPostedTime()) == date('Ymd')) {
-    $variables['source_date'] = t('%ago ago', array('%ago' => format_interval(REQUEST_TIME - $item->getPostedTime())));
-  }
-  else {
-    $variables['source_date'] = format_date($item->getPostedTime(), 'medium');
+  $item = $variables['elements']['#aggregator_item'];
+
+  // Helpful $content variable for templates.
+  foreach (element_children($variables['elements']) as $key) {
+    $variables['content'][$key] = $variables['elements'][$key];
   }
 
+  // Preprocess fields.
+  field_attach_preprocess($item, $variables['elements'], $variables);
+
+  $variables['url'] = check_url($item->getLink());
+  $variables['title'] = check_plain($item->label());
+
   $variables['attributes']['class'][] = 'feed-item';
 }
 
@@ -107,102 +100,49 @@ function theme_aggregator_page_opml($variables) {
 }
 
 /**
- * Prepares variables for aggregator summary templates.
+ * Prepares variables for aggregator feed templates.
  *
- * Default template: aggregator-summary-items.html.twig.
+ * Default template: aggregator-feed.html.twig.
  *
  * @param array $variables
  *   An associative array containing:
- *   - source: A Drupal\aggregator\Entity\Feed instance representing
- *     the feed source.
- *   - summary_items: An array of feed items.
+ *   - elements: An array of elements to display in view mode.
  */
-function template_preprocess_aggregator_summary_items(&$variables) {
-  $variables['title'] = check_plain($variables['source'] instanceof EntityInterface ? $variables['source']->label() : $variables['source']->title);
-  $summary_items = array();
-  foreach (element_children($variables['summary_items']) as $key) {
-    $summary_items[] = $variables['summary_items'][$key];
+function template_preprocess_aggregator_feed(&$variables) {
+  $feed = $variables['elements']['#aggregator_feed'];
+
+  // Helpful $content variable for templates.
+  foreach (element_children($variables['elements']) as $key) {
+    $variables['content'][$key] = $variables['elements'][$key];
   }
-  $variables['summary_list'] = array(
-    '#theme' => 'item_list',
-    '#items' => $summary_items,
-  );
-  $variables['source_url'] = $variables['source'] instanceof EntityInterface ? $variables['source']->url->value : $variables['source']->url;
-}
 
-/**
- * Processes variables for aggregator summary item templates.
- *
- * Default template: aggregator-summary-item.html.twig.
- *
- * @param array $variables
- *   An associative array containing:
- *   - aggregator_item: The feed item.
- *   - view_mode: How the item is being displayed.
- */
-function template_preprocess_aggregator_summary_item(&$variables) {
-  $item = $variables['aggregator_item'];
-
-  $variables['url'] = l(check_plain($item->label()), check_url(url($item->getLink(), array('absolute' => TRUE))), array(
-    'attributes' => array(
-      'class' => array('feed-item-url'),
-    ),
-  ));
-  $variables['age'] = array(
-    '#theme' => 'datetime',
-    '#attributes' => array(
-      'datetime' => format_date($item->getPostedTime(), 'html_datetime', '', 'UTC'),
-      'class' => array('feed-item-age',),
-    ),
-    '#text' => t('%age old', array('%age' => format_interval(REQUEST_TIME - $item->getPostedTime()))),
-    '#html' => TRUE,
-  );
-}
+  // Preprocess fields.
+  field_attach_preprocess($feed, $variables['elements'], $variables);
 
-/**
- * Prepares variables for aggregator feed source templates.
- *
- * Default template: aggregator-feed-source.html.twig.
- *
- * @param array $variables
- *   An associative array containing:
- *   - aggregator_feed: A Drupal\aggregator\Entity\Feed instance
- *     representing the feed source.
- */
-function template_preprocess_aggregator_feed_source(&$variables) {
-  $feed = $variables['aggregator_feed'];
-
-  $feed_icon = array(
-    '#theme' => 'feed_icon',
-    '#url' => $feed->url->value,
-    '#title' => t('!title feed', array('!title' => $feed->label())),
-  );
-  $variables['source_icon'] = drupal_render($feed_icon);
-
-  if (!empty($feed->image->value) && $feed->label() && !empty($feed->link->value)) {
-    $image = array(
-      '#theme' => 'image',
-      '#path' => $feed->image->value,
-      '#alt' => $feed->title->value,
+  $variables['full'] = $variables['elements']['#view_mode'] == 'full';
+  $variables['title'] = String::checkPlain($feed->label());
+  if ($variables['full']) {
+    $variables['link'] = array(
+      '#theme' => 'feed_icon',
+      '#url' => $feed->url->value,
+      '#title' => t('!title feed', array('!title' => $feed->label())),
     );
-    $variables['source_image'] = l($image, $feed->link->value, array('html' => TRUE, 'attributes' => array('class' => 'feed-image')));
-  }
-  else {
-    $variables['source_image'] = '';
-  }
-  $variables['source_description'] = aggregator_filter_xss($feed->description->value);
-  $variables['source_url'] = check_url(url($feed->link->value, array('absolute' => TRUE)));
-
-  if ($feed->checked) {
-    $variables['last_checked'] = t('@time ago', array('@time' => format_interval(REQUEST_TIME - $feed->checked->value)));
   }
   else {
-    $variables['last_checked'] = t('never');
-  }
-
-  if (\Drupal::currentUser()->hasPermission('administer news feeds')) {
-    $variables['last_checked'] = l($variables['last_checked'], 'admin/config/services/aggregator');
+    $title_stripped = strip_tags($feed->label());
+    $variables['link'] = array(
+      '#type' => 'link',
+      '#title' => t('More<span class="visually-hidden"> posts about @title</span>', array(
+        '@title' => $title_stripped,
+      )),
+      '#href' => 'aggregator/sources/' . $feed->id(),
+      '#options' => array(
+        'html' => TRUE,
+        'attributes' => array(
+          'title' => $title_stripped,
+        ),
+      ),
+    );
   }
-
   $variables['attributes']['class'][] = 'feed-source';
 }
diff --git a/core/modules/aggregator/config/entity.display.aggregator_feed.aggregator_feed.default.yml b/core/modules/aggregator/config/entity.display.aggregator_feed.aggregator_feed.default.yml
new file mode 100644
index 0000000..651dc9f
--- /dev/null
+++ b/core/modules/aggregator/config/entity.display.aggregator_feed.aggregator_feed.default.yml
@@ -0,0 +1,22 @@
+id: aggregator_feed.aggregator_feed.default
+uuid: 55a2c421-541c-412a-a905-5de49aedd230
+targetEntityType: aggregator_feed
+bundle: aggregator_feed
+mode: default
+content:
+  items:
+    weight: '0'
+    visible: true
+  link:
+    weight: '3'
+    visible: true
+  checked:
+    weight: '0'
+    visible: true
+  description:
+    weight: '2'
+    visible: true
+  image:
+    weight: '1'
+    visible: true
+status: true
diff --git a/core/modules/aggregator/config/entity.display.aggregator_feed.aggregator_feed.teaser.yml b/core/modules/aggregator/config/entity.display.aggregator_feed.aggregator_feed.teaser.yml
new file mode 100644
index 0000000..3b6e0d6
--- /dev/null
+++ b/core/modules/aggregator/config/entity.display.aggregator_feed.aggregator_feed.teaser.yml
@@ -0,0 +1,18 @@
+id: aggregator_feed.aggregator_feed.teaser
+uuid: ddb01083-25d8-44d5-8209-9c17295151ac
+targetEntityType: aggregator_feed
+bundle: aggregator_feed
+mode: teaser
+content:
+  items:
+    weight: '0'
+    visible: true
+  link:
+    visible: false
+  checked:
+    visible: false
+  description:
+    visible: false
+  image:
+    visible: false
+status: true
diff --git a/core/modules/aggregator/config/entity.display.aggregator_item.aggregator_item.default.yml b/core/modules/aggregator/config/entity.display.aggregator_item.aggregator_item.default.yml
new file mode 100644
index 0000000..950c724
--- /dev/null
+++ b/core/modules/aggregator/config/entity.display.aggregator_item.aggregator_item.default.yml
@@ -0,0 +1,20 @@
+id: aggregator_item.aggregator_item.default
+uuid: d385a0b6-d5e4-45b1-bf0d-1304c6bf1004
+targetEntityType: aggregator_item
+bundle: aggregator_item
+mode: default
+content:
+  feed:
+    weight: '0'
+    visible: true
+  link:
+    visible: false
+  author:
+    visible: false
+  description:
+    weight: '2'
+    visible: true
+  timestamp:
+    weight: '1'
+    visible: true
+status: true
diff --git a/core/modules/aggregator/config/entity.display.aggregator_item.aggregator_item.teaser.yml b/core/modules/aggregator/config/entity.display.aggregator_item.aggregator_item.teaser.yml
new file mode 100644
index 0000000..d1a36e7
--- /dev/null
+++ b/core/modules/aggregator/config/entity.display.aggregator_item.aggregator_item.teaser.yml
@@ -0,0 +1,18 @@
+id: aggregator_item.aggregator_item.teaser
+uuid: e13e67db-b30e-4023-bd20-32c237ef0c17
+targetEntityType: aggregator_item
+bundle: aggregator_item
+mode: teaser
+content:
+  feed:
+    visible: false
+  link:
+    visible: false
+  author:
+    visible: false
+  description:
+    visible: false
+  timestamp:
+    weight: '0'
+    visible: true
+status: true
diff --git a/core/modules/aggregator/config/entity.view_mode.aggregator_feed.teaser.yml b/core/modules/aggregator/config/entity.view_mode.aggregator_feed.teaser.yml
new file mode 100644
index 0000000..1cabe2a
--- /dev/null
+++ b/core/modules/aggregator/config/entity.view_mode.aggregator_feed.teaser.yml
@@ -0,0 +1,7 @@
+id: aggregator_feed.teaser
+uuid: 92109a57-3084-4ddb-8443-67341b0bbbde
+label: Teaser
+targetEntityType: aggregator_feed
+status: true
+cache: true
+langcode: en
diff --git a/core/modules/aggregator/config/entity.view_mode.aggregator_item.teaser.yml b/core/modules/aggregator/config/entity.view_mode.aggregator_item.teaser.yml
new file mode 100644
index 0000000..ac8928b
--- /dev/null
+++ b/core/modules/aggregator/config/entity.view_mode.aggregator_item.teaser.yml
@@ -0,0 +1,7 @@
+id: aggregator_item.teaser
+uuid: 80d08a44-d827-47bc-a547-715148406089
+label: Teaser
+targetEntityType: aggregator_item
+status: true
+cache: true
+langcode: en
diff --git a/core/modules/aggregator/config/views.view.aggregator_sources.yml b/core/modules/aggregator/config/views.view.aggregator_sources.yml
new file mode 100644
index 0000000..15aa274
--- /dev/null
+++ b/core/modules/aggregator/config/views.view.aggregator_sources.yml
@@ -0,0 +1,128 @@
+base_field: fid
+base_table: aggregator_feed
+core: 8.x
+description: ''
+status: true
+display:
+  default:
+    display_plugin: default
+    id: default
+    display_title: Master
+    position: 1
+    display_options:
+      access:
+        type: none
+        options: {  }
+      cache:
+        type: none
+        options: {  }
+      query:
+        type: views_query
+        options:
+          disable_sql_rewrite: false
+          distinct: false
+          slave: false
+          query_comment: ''
+          query_tags: {  }
+      exposed_form:
+        type: basic
+        options:
+          submit_button: Apply
+          reset_button: false
+          reset_button_label: Reset
+          exposed_sorts_label: 'Sort by'
+          expose_sort_order: true
+          sort_asc_label: Asc
+          sort_desc_label: Desc
+      pager:
+        type: none
+        options:
+          offset: '0'
+      style:
+        type: default
+      row:
+        type: 'entity:aggregator_feed'
+        options:
+          relationship: none
+          view_mode: teaser
+      fields:
+        fid:
+          table: aggregator_feed
+          field: fid
+          id: fid
+          plugin_id: numeric
+          provider: views
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: 'Feed ID'
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: ''
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          set_precision: false
+          precision: 0
+          decimal: .
+          separator: ','
+          format_plural: false
+          format_plural_singular: '1'
+          format_plural_plural: '@count'
+          prefix: ''
+          suffix: ''
+      filters: {  }
+      sorts: {  }
+      title: Sources
+      header: {  }
+      footer: {  }
+      empty: {  }
+      relationships: {  }
+      arguments: {  }
+  page_1:
+    display_plugin: page
+    id: page_1
+    display_title: Page
+    position: 1
+    display_options:
+      path: aggregator/sources
+label: 'Aggregator sources'
+module: views
+id: aggregator_sources
+tag: ''
+uuid: de727db1-189f-4bfb-8d06-6a566d4dd02c
+langcode: en
diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Entity/Feed.php b/core/modules/aggregator/lib/Drupal/aggregator/Entity/Feed.php
index 01d6d7d..3809b1d 100644
--- a/core/modules/aggregator/lib/Drupal/aggregator/Entity/Feed.php
+++ b/core/modules/aggregator/lib/Drupal/aggregator/Entity/Feed.php
@@ -35,6 +35,11 @@
  *   entity_keys = {
  *     "id" = "fid",
  *     "label" = "title",
+ *   },
+ *   links = {
+ *     "canonical" = "aggregator.feed_view",
+ *     "edit-form" = "aggregator.feed_configure",
+ *     "admin-form" = "aggregator.admin_overview"
  *   }
  * )
  */
diff --git a/core/modules/aggregator/lib/Drupal/aggregator/FeedViewBuilder.php b/core/modules/aggregator/lib/Drupal/aggregator/FeedViewBuilder.php
index 853122f..c442e18 100644
--- a/core/modules/aggregator/lib/Drupal/aggregator/FeedViewBuilder.php
+++ b/core/modules/aggregator/lib/Drupal/aggregator/FeedViewBuilder.php
@@ -8,7 +8,10 @@
 namespace Drupal\aggregator;
 
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityManager;
 use Drupal\Core\Entity\EntityViewBuilder;
+use Drupal\Core\Config\Config;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Render controller for aggregator feed items.
@@ -16,12 +19,132 @@
 class FeedViewBuilder extends EntityViewBuilder {
 
   /**
+   * Constructs a new EntityViewBuilder.
+   *
+   * @param string $entity_type
+   *   The entity type.
+   * @param array $entity_info
+   *   The entity information array.
+   * @param \Drupal\Core\Entity\EntityManager $entity_manager
+   *   The entity manager service.
+   * @param \Drupal\Core\Config\Config $config
+   *   The configuration object for aggregator.settings.
+   */
+  public function __construct($entity_type, array $entity_info, EntityManager $entity_manager, Config $config) {
+    parent::__construct($entity_type, $entity_info, $entity_manager);
+    $this->config = $config;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function createInstance(ContainerInterface $container, $entity_type, array $entity_info) {
+    return new static(
+      $entity_type,
+      $entity_info,
+      $container->get('entity.manager'),
+      $container->get('config.factory')->get('aggregator.settings')
+    );
+  }
+
+  /**
    * {@inheritdoc}
    */
-  protected function getBuildDefaults(EntityInterface $entity, $view_mode, $langcode) {
-    $defaults = parent::getBuildDefaults($entity, $view_mode, $langcode);
-    $defaults['#theme'] = 'aggregator_feed_source';
-    return $defaults;
+  public function buildContent(array $entities, array $displays, $view_mode, $langcode = NULL) {
+    $return = array();
+    if (empty($entities)) {
+      return $return;
+    }
+
+    parent::buildContent($entities, $displays, $view_mode, $langcode);
+
+    foreach ($entities as $entity) {
+      $bundle = $entity->bundle();
+      $display = $displays[$bundle];
+
+      if ($display->getComponent('items')) {
+        // When not in full view mode respect the list_max setting.
+        $limit = $view_mode != 'full' ? $this->config->get('source.list_max') : NULL;
+        // Retrieve the items attached to this feed.
+        $items = $this->entityManager
+          ->getStorageController('aggregator_item')
+          ->loadByFeed($entity->id(), $limit);
+
+        $rendered = $this->entityManager
+          ->getViewBuilder('aggregator_item')
+          ->viewMultiple($items, $view_mode, $langcode);
+
+        foreach (element_children($rendered) as $key) {
+          $list[] = $rendered[$key];
+        }
+        // Items should be rendered in a HTML list.
+        $entity->content['items'] = array(
+          '#theme' => 'item_list',
+          '#items' => $list,
+        );
+      }
+
+      if ($display->getComponent('link')) {
+        $entity->content['link'] = array(
+          '#type' => 'link',
+          '#href' => $entity->link->value,
+          '#title' => $entity->link->value,
+          '#options' => array('absolute' => TRUE),
+          '#prefix' => '<div class="feed-url">' . t('<em>URL:</em>') . ' ',
+          '#suffix' => '</div>',
+        );
+      }
+
+      if ($display->getComponent('checked')) {
+        // Render the checked timestamp as time ago.
+        if ($entity->checked) {
+          $updated = t('@time ago', array('@time' => format_interval(REQUEST_TIME - $entity->checked->value)));
+        }
+        else {
+          $updated = t('never');
+        }
+        $entity->content['checked'] = array(
+          '#markup' => t('<em>Updated:</em> @updated', array('@updated' => $updated)),
+          '#prefix' => '<div class="feed-updated">',
+          '#suffix' => '</div>',
+        );
+      }
+
+      if ($display->getComponent('description')) {
+        $entity->content['description'] = array(
+          '#markup' => aggregator_filter_xss($entity->description->value),
+          '#prefix' => '<div class="feed-description">',
+          '#suffix' => '</div>',
+        );
+      }
+
+      if ($display->getComponent('image')) {
+        // Render the image as link if it is available.
+        if (!empty($entity->image->value) && $entity->label() && !empty($entity->link->value)) {
+          $image = array(
+            '#theme' => 'image',
+            '#path' => $entity->image->value,
+            '#alt' => $entity->title->value,
+          );
+          $image_link = array(
+            '#type' => 'link',
+            '#title' => $image,
+            '#href' => $entity->link->value,
+            '#options' => array(
+              'attributes' => array('class' => array('feed-image')),
+              'html' => TRUE,
+            ),
+          );
+        }
+        else {
+          $image_link = '';
+        }
+        $entity->content['image'] = array(
+          '#markup' => $image_link,
+        );
+      }
+
+    }
   }
 
 }
diff --git a/core/modules/aggregator/lib/Drupal/aggregator/ItemViewBuilder.php b/core/modules/aggregator/lib/Drupal/aggregator/ItemViewBuilder.php
index 7d3f919..a582b29 100644
--- a/core/modules/aggregator/lib/Drupal/aggregator/ItemViewBuilder.php
+++ b/core/modules/aggregator/lib/Drupal/aggregator/ItemViewBuilder.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\aggregator;
 
+use Drupal\Component\Utility\String;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityViewBuilder;
 
@@ -18,14 +19,93 @@ class ItemViewBuilder extends EntityViewBuilder {
   /**
    * {@inheritdoc}
    */
-  protected function getBuildDefaults(EntityInterface $entity, $view_mode, $langcode) {
-    $defaults = parent::getBuildDefaults($entity, $view_mode, $langcode);
+  public function buildContent(array $entities, array $displays, $view_mode, $langcode = NULL) {
+    $return = array();
+    if (empty($entities)) {
+      return $return;
+    }
+
+    parent::buildContent($entities, $displays, $view_mode, $langcode);
+
+    foreach ($entities as $entity) {
+      $bundle = $entity->bundle();
+      $display = $displays[$bundle];
+
+      if ($display->getComponent('feed')) {
+        // Retrieve the feed.
+        $feed = $this->entityManager
+          ->getStorageController('aggregator_feed')
+          ->load($entity->getFeedId());
+
+        // Render the feed title as well a link to it.
+        $entity->content['items']['feed'] = array(
+          '#type' => 'link',
+          '#title' => $feed->label(),
+          '#href' => 'aggregator/sources/' . $feed->id(),
+          '#options' => array(
+            'attributes' => array('class' => array('feed-item-source')),
+          ),
+          '#prefix' => '<div class="feed-source-meta">',
+          '#suffix' => '</div>',
+        );
+      }
+
+      if ($display->getComponent('link')) {
+        $entity->content['link'] = array(
+          '#type' => 'link',
+          '#href' => $entity->getLink(),
+          '#title' => $entity->label(),
+          '#options' => array('absolute' => TRUE),
+        );
+      }
+
+      if ($display->getComponent('timestamp')) {
+        if ($view_mode == 'teaser') {
+          // Always render the timestamp as time ago on teaser.
+          $entity->content['timestamp'] = array(
+            '#theme' => 'datetime',
+            '#attributes' => array(
+              'datetime' => format_date($entity->getPostedTime(), 'html_datetime', '', 'UTC'),
+              'class' => array('feed-item-age',),
+            ),
+            '#text' => t('%age old', array('%age' => format_interval(REQUEST_TIME - $entity->getPostedTime()))),
+            '#html' => TRUE,
+          );
+        }
+        else {
+          // On full mode only display as time ago only if the post is in the
+          // same month.
+          if (date('Ymd', $entity->getPostedTime()) == date('Ymd')) {
+            $date = t('%ago ago', array('%ago' => format_interval(REQUEST_TIME - $entity->getPostedTime())));
+          }
+          else {
+            $date = format_date($entity->getPostedTime(), 'medium');
+          }
+          $entity->content['timestamp'] = array(
+            '#markup' => $date,
+            '#prefix' => '<span class="feed-item-date">',
+            '#suffix' => '</span>',
+          );
+        }
+      }
+
+      if ($display->getComponent('description')) {
+        $entity->content['description'] = array(
+          '#markup' => aggregator_filter_xss($entity->getDescription()),
+          '#prefix' => '<div class="item-description">',
+          '#suffix' => '</div>',
+        );
+      }
+
+      if ($display->getComponent('author')) {
+        $entity->content['author'] = array(
+          '#markup' => String::checkPlain($entity->getAuthor()),
+          '#prefix' => '<span class="item-author">',
+          '#suffix' => '</span>',
+        );
+      }
 
-    // Use a different template for the summary view mode.
-    if ($view_mode == 'summary') {
-      $defaults['#theme'] = 'aggregator_summary_item';
     }
-    return $defaults;
   }
 
 }
diff --git a/core/modules/aggregator/templates/aggregator-feed-source.html.twig b/core/modules/aggregator/templates/aggregator-feed-source.html.twig
deleted file mode 100644
index 5f13425..0000000
--- a/core/modules/aggregator/templates/aggregator-feed-source.html.twig
+++ /dev/null
@@ -1,34 +0,0 @@
-{#
-/**
- * @file
- * Default theme implementation to present the source of the feed.
- *
- * The contents are rendered above feed listings when browsing source feeds.
- * For example, "example.com/aggregator/sources/1".
- *
- * Available variables:
- * - source_icon: Feed icon linked to the source. Rendered through
- *   feed-icon.html.twig.
- * - source_image: Image set by the feed source.
- * - source_description: Description set by the feed source.
- * - source_url: URL to the feed source.
- * - last_checked: How long ago the feed was checked locally.
- *
- * @see template_preprocess_aggregator_feed_source()
- *
- * @ingroup themeable
- */
-#}
-<div{{ attributes}}>
-  {{ source_icon }}
-  {{ source_image }}
-  <div class="feed-description">
-    {{ source_description }}
-  </div>
-  <div class="feed-url">
-    <em>{{ 'URL'|t }}:</em> <a href="{{ source_url }}">{{ source_url }}</a>
-  </div>
-  <div class="feed-updated">
-    <em>{{ 'Updated'|t }}:</em> {{ last_checked }}
-  </div>
-</div>
diff --git a/core/modules/aggregator/templates/aggregator-feed.html.twig b/core/modules/aggregator/templates/aggregator-feed.html.twig
new file mode 100644
index 0000000..3f569d3
--- /dev/null
+++ b/core/modules/aggregator/templates/aggregator-feed.html.twig
@@ -0,0 +1,34 @@
+{#
+/**
+ * @file
+ * Default theme implementation to present an aggregator feed.
+ *
+ * The contents are rendered above feed listings when browsing source feeds.
+ * For example, "example.com/aggregator/sources/1".
+ *
+ * Available variables:
+ * - title: Title of the feed item.
+ * - link: A "Read more" link on teaser view mode, a feed icon on full mode.
+ * - content: All field items. Use {{ content }} to print them all,
+ *   or print a subset such as {{ content.field_example }}. Use
+ *   {% hide(content.field_example) %} to temporarily suppress the printing
+ *   of a given element.
+ *
+ * @see template_preprocess_aggregator_feed()
+ *
+ * @ingroup themeable
+ */
+#}
+<div{{ attributes}}>
+
+  {{ title_prefix }}
+  {% if not full %}
+    <h2{{ title_attributes }}>{{ title }}</h2>
+  {% endif %}
+  {{ title_suffix }}
+
+  {{ content }}
+
+  {{ link }}
+
+</div>
diff --git a/core/modules/aggregator/templates/aggregator-item.html.twig b/core/modules/aggregator/templates/aggregator-item.html.twig
index 8c23106..ff6be1f 100644
--- a/core/modules/aggregator/templates/aggregator-item.html.twig
+++ b/core/modules/aggregator/templates/aggregator-item.html.twig
@@ -4,12 +4,12 @@
  * Default theme implementation to present a feed item in an aggregator page.
  *
  * Available variables:
- * - feed_url: URL to the originating feed item.
- * - feed_title: Title of the feed item.
- * - source_url: Link to the local source section.
- * - source_title: Title of the remote source.
- * - source_date: Date the feed was posted on the remote source.
- * - content: Feed item content.
+ * - url: URL to the originating feed item.
+ * - title: Title of the feed item.
+ * - content: All field items. Use {{ content }} to print them all,
+ *   or print a subset such as {{ content.field_example }}. Use
+ *   {% hide(content.field_example) %} to temporarily suppress the printing
+ *   of a given element.
  *
  * @see template_preprocess_aggregator_item()
  *
@@ -17,20 +17,12 @@
  */
 #}
 <div{{ attributes }}>
+  {{ title_prefix }}
   <h3 class="feed-item-title">
-    <a href="{{ feed_url }}">{{ feed_title }}</a>
+    <a href="{{ url }}">{{ title }}</a>
   </h3>
+  {{ title_suffix }}
 
-  <div class="feed-item-meta">
-    {% if source_url %}
-      <a href="{{ source_url }}" class="feed-item-source">{{ source_title }}</a> -
-    {% endif %}
-    <span class="feed-item-date">{{ source_date }}</span>
-  </div>
+  {{ content }}
 
-  {% if content %}
-    <div class="feed-item-body">
-      {{ content }}
-    </div>
-  {% endif %}
 </div>
diff --git a/core/modules/aggregator/templates/aggregator-summary-item.html.twig b/core/modules/aggregator/templates/aggregator-summary-item.html.twig
deleted file mode 100644
index 3cb2279..0000000
--- a/core/modules/aggregator/templates/aggregator-summary-item.html.twig
+++ /dev/null
@@ -1,15 +0,0 @@
-{#
-/**
- * @file
- * Default theme implementation for a single feed in a list of feed items.
- *
- * Available variables:
- * - url: URL of item.
- * - age: Age of the item.
- *
- * @see template_preprocess_aggregator_summary_item()
- *
- * @ingroup themeable
- */
-#}
-{{ url }} {{ age }}
diff --git a/core/modules/aggregator/templates/aggregator-summary-items.html.twig b/core/modules/aggregator/templates/aggregator-summary-items.html.twig
deleted file mode 100644
index a00b8dc..0000000
--- a/core/modules/aggregator/templates/aggregator-summary-items.html.twig
+++ /dev/null
@@ -1,23 +0,0 @@
-{#
-/**
- * @file
- * Default theme implementation to present feeds as list items.
- *
- * Each iteration generates a single feed source.
- *
- * Available variables:
- * - title: Title of the feed.
- * - summary_list: Unordered list of linked feed items generated through
- *   theme_item_list().
- * - source_url: URL to the local source.
- *
- * @see template_preprocess_aggregator_summary_items()
- *
- * @ingroup themeable
- */
-#}
-<h3>{{ title }}</h3>
-{{ summary_list }}
-<div class="links">
-  <a href="{{ source_url }}">{% trans %}More<span class="visually-hidden"> posts about {{ title|placeholder }}</span>{% endtrans %}</a>
-</div>
