diff --git a/core/config/schema/core.entity.schema.yml b/core/config/schema/core.entity.schema.yml
index df2a2fd..139fd40 100644
--- a/core/config/schema/core.entity.schema.yml
+++ b/core/config/schema/core.entity.schema.yml
@@ -78,6 +78,27 @@ core.entity_view_display.*.*.*:
              label: 'Third party settings'
              sequence:
                type: field.formatter.third_party.[%key]
+    blocks:
+      type: sequence
+      label: 'Block fields'
+      sequence:
+        type: mapping
+        mapping:
+          machine_name:
+            type: string
+            label: 'ID'
+          plugin_id:
+            type: string
+            label: 'Plugin ID'
+          weight:
+            type: integer
+            label: 'Weight'
+          region:
+            type: string
+            label: 'Region'
+          settings:
+            type: block.settings.[id]
+
     hidden:
       type: sequence
       label: 'Field display setting'
diff --git a/core/lib/Drupal/Core/Entity/Display/EntityViewDisplayInterface.php b/core/lib/Drupal/Core/Entity/Display/EntityViewDisplayInterface.php
index 3598b51..a930f30 100644
--- a/core/lib/Drupal/Core/Entity/Display/EntityViewDisplayInterface.php
+++ b/core/lib/Drupal/Core/Entity/Display/EntityViewDisplayInterface.php
@@ -46,4 +46,24 @@ public function build(FieldableEntityInterface $entity);
    */
   public function buildMultiple(array $entities);
 
+  /**
+   * @todo.
+   */
+  public function getBlocks();
+
+  /**
+   * @todo.
+   */
+  public function getBlock($name);
+
+  /**
+   * @todo.
+   */
+  public function removeBlock($name);
+
+  /**
+   * @todo.
+   */
+  public function setBlock($name, $block);
+
 }
diff --git a/core/lib/Drupal/Core/Entity/Entity/EntityViewDisplay.php b/core/lib/Drupal/Core/Entity/Entity/EntityViewDisplay.php
index 74b15b6..4a26e8e 100644
--- a/core/lib/Drupal/Core/Entity/Entity/EntityViewDisplay.php
+++ b/core/lib/Drupal/Core/Entity/Entity/EntityViewDisplay.php
@@ -8,6 +8,7 @@
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\FieldableEntityInterface;
 use Drupal\Core\Entity\EntityDisplayBase;
+use Drupal\Core\Plugin\ContextAwarePluginInterface;
 use Drupal\Core\TypedData\TranslatableInterface;
 
 /**
@@ -27,6 +28,7 @@
  *     "bundle",
  *     "mode",
  *     "content",
+ *     "blocks",
  *     "hidden",
  *   }
  * )
@@ -39,6 +41,44 @@ class EntityViewDisplay extends EntityDisplayBase implements EntityViewDisplayIn
   protected $displayContext = 'view';
 
   /**
+   * @todo.
+   *
+   * @var array
+   */
+  protected $blocks = [];
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getBlocks() {
+    return $this->blocks;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getBlock($name) {
+    $blocks = $this->getBlocks();
+    return isset($blocks[$name]) ? $blocks[$name] : NULL;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function removeBlock($name) {
+    unset($this->blocks[$name]);
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setBlock($name, $block) {
+    $this->blocks[$name] = $block;
+    return $this;
+  }
+
+  /**
    * Returns the display objects used to render a set of entities.
    *
    * Depending on the configuration of the view mode for each bundle, this can
@@ -263,6 +303,24 @@ public function buildMultiple(array $entities) {
       }
     }
 
+    foreach ($this->getBlocks() as $name => $block_info) {
+      if ($block_info['region'] !== 'hidden') {
+        /** @var \Drupal\Core\Block\BlockPluginInterface $block */
+        $block = \Drupal::service('plugin.manager.block')->createInstance($block_info['plugin_id'], $block_info['settings']);
+
+        if ($block instanceof ContextAwarePluginInterface) {
+          $contexts = \Drupal::service('context.repository')->getRuntimeContexts($block->getContextMapping());
+          \Drupal::service('context.handler')->applyContextMapping($block, $contexts);
+        }
+
+        $block_access = $block->access(\Drupal::currentUser(), TRUE);
+        foreach ($entities as $id => $entity) {
+          $build_list[$id][$name] = $block_access->isAllowed() ? $block->build() : [];
+          $this->renderer->addCacheableDependency($build_list[$id][$name], $block_access);
+        }
+      }
+    }
+
     foreach ($entities as $id => $entity) {
       // Assign the configured weights.
       foreach ($this->getComponents() as $name => $options) {
diff --git a/core/modules/aggregator/config/install/core.entity_view_display.aggregator_feed.aggregator_feed.default.yml b/core/modules/aggregator/config/install/core.entity_view_display.aggregator_feed.aggregator_feed.default.yml
index e0232cf..1b8a7e1 100644
--- a/core/modules/aggregator/config/install/core.entity_view_display.aggregator_feed.aggregator_feed.default.yml
+++ b/core/modules/aggregator/config/install/core.entity_view_display.aggregator_feed.aggregator_feed.default.yml
@@ -34,5 +34,6 @@ content:
     settings: {  }
     third_party_settings: {  }
     label: inline
+blocks: {  }
 hidden:
   more_link: true
diff --git a/core/modules/aggregator/config/install/core.entity_view_display.aggregator_feed.aggregator_feed.summary.yml b/core/modules/aggregator/config/install/core.entity_view_display.aggregator_feed.aggregator_feed.summary.yml
index 5e5e468..7128751 100644
--- a/core/modules/aggregator/config/install/core.entity_view_display.aggregator_feed.aggregator_feed.summary.yml
+++ b/core/modules/aggregator/config/install/core.entity_view_display.aggregator_feed.aggregator_feed.summary.yml
@@ -16,6 +16,7 @@ content:
   more_link:
     weight: 1
     region: content
+blocks: {  }
 hidden:
   checked: true
   description: true
diff --git a/core/modules/aggregator/config/install/core.entity_view_display.aggregator_item.aggregator_item.summary.yml b/core/modules/aggregator/config/install/core.entity_view_display.aggregator_item.aggregator_item.summary.yml
index 8e29395..7b40b0c 100644
--- a/core/modules/aggregator/config/install/core.entity_view_display.aggregator_item.aggregator_item.summary.yml
+++ b/core/modules/aggregator/config/install/core.entity_view_display.aggregator_item.aggregator_item.summary.yml
@@ -13,6 +13,7 @@ content:
   timestamp:
     weight: 0
     region: content
+blocks: {  }
 hidden:
   author: true
   description: true
diff --git a/core/modules/book/config/optional/core.entity_view_display.node.book.default.yml b/core/modules/book/config/optional/core.entity_view_display.node.book.default.yml
index d6ef64d..5aafb59 100644
--- a/core/modules/book/config/optional/core.entity_view_display.node.book.default.yml
+++ b/core/modules/book/config/optional/core.entity_view_display.node.book.default.yml
@@ -22,4 +22,5 @@ content:
   links:
     weight: 101
     region: content
+blocks: {  }
 hidden: {  }
diff --git a/core/modules/book/config/optional/core.entity_view_display.node.book.teaser.yml b/core/modules/book/config/optional/core.entity_view_display.node.book.teaser.yml
index 77a62c3..14ae374 100644
--- a/core/modules/book/config/optional/core.entity_view_display.node.book.teaser.yml
+++ b/core/modules/book/config/optional/core.entity_view_display.node.book.teaser.yml
@@ -24,4 +24,5 @@ content:
   links:
     weight: 101
     region: content
+blocks: {  }
 hidden: {  }
diff --git a/core/modules/field_layout/tests/src/Kernel/FieldLayoutEntityDisplayTest.php b/core/modules/field_layout/tests/src/Kernel/FieldLayoutEntityDisplayTest.php
index 3ca5e59..65ef50a 100644
--- a/core/modules/field_layout/tests/src/Kernel/FieldLayoutEntityDisplayTest.php
+++ b/core/modules/field_layout/tests/src/Kernel/FieldLayoutEntityDisplayTest.php
@@ -56,6 +56,7 @@ public function testPreSave() {
           'type' => 'hidden',
         ],
       ],
+      'blocks' => [],
       'hidden' => [],
     ];
     $this->assertEntityValues($expected, $entity_display->toArray());
diff --git a/core/modules/field_ui/field_ui.module b/core/modules/field_ui/field_ui.module
index 79b3f15..324942e 100644
--- a/core/modules/field_ui/field_ui.module
+++ b/core/modules/field_ui/field_ui.module
@@ -11,6 +11,7 @@
 use Drupal\Core\Entity\EntityViewModeInterface;
 use Drupal\Core\Entity\EntityFormModeInterface;
 use Drupal\Core\Url;
+use Drupal\field_ui\Form\EntityViewDisplayAddBlockForm;
 use Drupal\field_ui\FieldUI;
 use Drupal\field_ui\Plugin\Derivative\FieldUiLocalTask;
 
@@ -81,6 +82,7 @@ function field_ui_entity_type_build(array &$entity_types) {
 
   $entity_types['entity_form_display']->setFormClass('edit', 'Drupal\field_ui\Form\EntityFormDisplayEditForm');
   $entity_types['entity_view_display']->setFormClass('edit', 'Drupal\field_ui\Form\EntityViewDisplayEditForm');
+  $entity_types['entity_view_display']->setFormClass('add_block', EntityViewDisplayAddBlockForm::class);
 
   $form_mode = $entity_types['entity_form_mode'];
   $form_mode->setListBuilderClass('Drupal\field_ui\EntityFormModeListBuilder');
diff --git a/core/modules/field_ui/src/Form/EntityViewDisplayAddBlockForm.php b/core/modules/field_ui/src/Form/EntityViewDisplayAddBlockForm.php
new file mode 100644
index 0000000..ba6e2d0
--- /dev/null
+++ b/core/modules/field_ui/src/Form/EntityViewDisplayAddBlockForm.php
@@ -0,0 +1,154 @@
+<?php
+
+namespace Drupal\field_ui\Form;
+
+use Drupal\Core\Block\BlockManagerInterface;
+use Drupal\Core\Entity\EntityForm;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Plugin\Context\ContextRepositoryInterface;
+use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\field_ui\FieldUI;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * @todo.
+ */
+class EntityViewDisplayAddBlockForm extends EntityForm {
+
+  /**
+   * The entity being used by this form.
+   *
+   * @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface
+   */
+  protected $entity;
+
+  /**
+   * The block manager.
+   *
+   * @var \Drupal\Core\Block\BlockManagerInterface
+   */
+  protected $blockManager;
+
+  /**
+   * The context repository.
+   *
+   * @var \Drupal\Core\Plugin\Context\LazyContextRepository
+   */
+  protected $contextRepository;
+
+  /**
+   * Constructs a new EntityViewDisplayAddBlockForm.
+   *
+   * @param \Drupal\Core\Block\BlockManagerInterface $block_manager
+   *   The block manager.
+   * @param \Drupal\Core\Plugin\Context\ContextRepositoryInterface $context_repository
+   *   The context repository.
+   */
+  public function __construct(BlockManagerInterface $block_manager, ContextRepositoryInterface $context_repository) {
+    $this->blockManager = $block_manager;
+    $this->contextRepository = $context_repository;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('plugin.manager.block'),
+      $container->get('context.repository'),
+      $container->get('entity_field.manager')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getEntityFromRouteMatch(RouteMatchInterface $route_match, $entity_type_id) {
+    $route_parameters = $route_match->getParameters()->all();
+
+    return entity_get_display($route_parameters['entity_type_id'], $route_parameters['bundle'], $route_parameters['view_mode_name']);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function form(array $form, FormStateInterface $form_state) {
+    $definitions = $this->blockManager->getDefinitionsForContexts($this->contextRepository->getAvailableContexts());
+    $definitions = $this->blockManager->getSortedDefinitions($definitions);
+
+    $options = [];
+    foreach ($definitions as $plugin_id => $plugin_definition) {
+      $options[$plugin_id] = [
+        'title' => $plugin_definition['admin_label'],
+        'category' => $plugin_definition['category'],
+      ];
+    }
+
+    $form['blocks'] = [
+      '#type' => 'tableselect',
+      '#header' => [
+        'title' => $this->t('Block'),
+        'category' => $this->t('Category'),
+      ],
+      '#options' => $options,
+      '#js_select' => FALSE,
+      '#empty' => $this->t('No blocks available.'),
+      '#element_validate' => [[$this, 'validateBlockValues']],
+    ];
+
+    return $form;
+  }
+
+  /**
+   * Transforms the list of new block IDs into full block info arrays.
+   */
+  public function validateBlockValues($element, FormStateInterface $form_state) {
+    $new_block_ids = array_keys(array_filter($form_state->getValue($element['#parents'])));
+    $existing_blocks = $this->entity->getBlocks();
+    foreach ($new_block_ids as $block_id) {
+      /** @var \Drupal\Core\Block\BlockPluginInterface $block */
+      $block = $this->blockManager->createInstance($block_id);
+
+      // Determine a unique machine name.
+      $suggestion = $block->getMachineNameSuggestion();
+      $count = 1;
+      $machine_name = $suggestion;
+      while (isset($existing_blocks[$machine_name])) {
+        $machine_name = $suggestion . '_' . ++$count;
+      }
+
+      $existing_blocks[$machine_name] = [
+        'machine_name' => $machine_name,
+        'plugin_id' => $block_id,
+        'settings' => $block->getConfiguration(),
+        'region' => 'content',
+        'weight' => 0,
+      ];
+    }
+    $form_state->setValueForElement($element, $existing_blocks);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, FormStateInterface $form_state) {
+    parent::submitForm($form, $form_state);
+
+    $entity_type = $this->entityTypeManager->getDefinition($this->entity->getTargetEntityTypeId());
+    $parameters = ['view_mode_name' => $this->entity->getMode()] + FieldUI::getRouteBundleParameter($entity_type, $this->entity->getTargetBundle());
+    $form_state->setRedirect('entity.entity_view_display.' . $this->entity->getTargetEntityTypeId() . '.view_mode', $parameters);
+
+    drupal_set_message($this->t('Your settings have been saved.'));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function actions(array $form, FormStateInterface $form_state) {
+    $actions = parent::actions($form, $form_state);
+    $actions['submit']['#value'] = $this->t('Add block');
+    return $actions;
+  }
+
+}
diff --git a/core/modules/field_ui/src/Form/EntityViewDisplayEditForm.php b/core/modules/field_ui/src/Form/EntityViewDisplayEditForm.php
index c27f3d4..1ff11e0 100644
--- a/core/modules/field_ui/src/Form/EntityViewDisplayEditForm.php
+++ b/core/modules/field_ui/src/Form/EntityViewDisplayEditForm.php
@@ -2,9 +2,16 @@
 
 namespace Drupal\field_ui\Form;
 
+use Drupal\Component\Plugin\ContextAwarePluginInterface;
+use Drupal\Component\Plugin\PluginManagerBase;
+use Drupal\Component\Serialization\Json;
+use Drupal\Core\Block\BlockManagerInterface;
+use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Field\FieldDefinitionInterface;
+use Drupal\Core\Field\FieldTypePluginManagerInterface;
 use Drupal\Core\Field\PluginSettingsInterface;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Form\SubformState;
 use Drupal\Core\Url;
 use Drupal\field_ui\FieldUI;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -15,6 +22,13 @@
 class EntityViewDisplayEditForm extends EntityDisplayFormBase {
 
   /**
+   * The entity being used by this form.
+   *
+   * @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface
+   */
+  protected $entity;
+
+  /**
    * {@inheritdoc}
    */
   protected $displayContext = 'view';
@@ -83,6 +97,236 @@ protected function buildExtraFieldRow($field_id, $extra_field) {
   /**
    * {@inheritdoc}
    */
+  public function form(array $form, FormStateInterface $form_state) {
+    $form = parent::form($form, $form_state);
+
+    $form_state->setTemporaryValue('gathered_contexts', \Drupal::service('context.repository')->getAvailableContexts());
+    foreach ($this->entity->getBlocks() as $block_id => $block_info) {
+      $form['fields'][$block_id] = $this->buildBlockFieldRow($block_id, $block_info, $form, $form_state);
+    }
+
+    $entity_type = $this->entityTypeManager->getDefinition($this->entity->getTargetEntityTypeId());
+    $parameters = ['view_mode_name' => $this->entity->getMode()] + FieldUI::getRouteBundleParameter($entity_type, $this->entity->getTargetBundle());
+    $url = Url::fromRoute('entity.entity_view_display.' . $this->entity->getTargetEntityTypeId() . '.add_block', $parameters);
+    $form['add_block'] = [
+      '#weight' => -100,
+      '#type' => 'link',
+      '#title' => $this->t('Add field block'),
+      '#url' => $url,
+      '#attributes' => [
+        'class' => ['use-ajax', 'button', 'button--small'],
+        'data-dialog-type' => 'modal',
+        'data-dialog-options' => Json::encode([
+          'width' => 700,
+        ]),
+      ],
+    ];
+    return $form;
+  }
+
+  /**
+   * @todo.
+   */
+  protected function getRouteBundleParameters($mode) {
+    $entity_type = $this->entityTypeManager->getDefinition($this->entity->getTargetEntityTypeId());
+    return ['view_mode_name' => $mode] + FieldUI::getRouteBundleParameter($entity_type, $this->entity->getTargetBundle());
+  }
+
+  /**
+   * @todo.
+   */
+  protected function buildBlockFieldRow($block_name, $block_info, $form, FormStateInterface $form_state) {
+    /** @var \Drupal\Core\Block\BlockPluginInterface $block */
+    $block_manager = \Drupal::service('plugin.manager.block');
+    $block = $block_manager->createInstance($block_info['plugin_id'], $block_info['settings']);
+
+    $regions = array_keys($this->getRegions());
+    $label = $block->label();
+    $block_field_row = [
+      '#attributes' => ['class' => ['draggable', 'tabledrag-leaf']],
+      '#row_type' => 'field',
+      '#region_callback' => [$this, 'getRowRegion'],
+      '#js_settings' => ['rowHandler' => 'field'],
+      'human_name' => [
+        '#markup' => $label,
+      ],
+      'weight' => [
+        '#type' => 'textfield',
+        '#title' => $this->t('Weight for @title', ['@title' => $label]),
+        '#title_display' => 'invisible',
+        '#default_value' => $block_info ? $block_info['weight'] : 0,
+        '#size' => 3,
+        '#attributes' => ['class' => ['field-weight']],
+      ],
+      'parent_wrapper' => [
+        'parent' => [
+          '#type' => 'select',
+          '#title' => $this->t('Parents for @title', ['@title' => $label]),
+          '#title_display' => 'invisible',
+          '#options' => array_combine($regions, $regions),
+          '#empty_value' => '',
+          '#attributes' => ['class' => ['js-field-parent', 'field-parent']],
+          '#parents' => ['fields', $block_name, 'parent'],
+        ],
+        'hidden_name' => [
+          '#type' => 'hidden',
+          '#default_value' => $block_name,
+          '#attributes' => ['class' => ['field-name']],
+        ],
+      ],
+      'region' => [
+        '#type' => 'select',
+        '#title' => $this->t('Region for @title', ['@title' => $label]),
+        '#title_display' => 'invisible',
+        '#options' => $this->getRegionOptions(),
+        '#default_value' => $block_info ? $block_info['region'] : 'visible',
+        '#attributes' => ['class' => ['field-region']],
+      ],
+      'empty_cell' => [
+        '#markup' => '&nbsp;',
+      ],
+      'plugin' => [
+        'type' => [
+          '#type' => 'hidden',
+          '#value' => $block_info ? 'visible' : 'hidden',
+          '#parents' => ['fields', $block_name, 'type'],
+          '#attributes' => ['class' => ['field-plugin-type']],
+        ],
+      ],
+      'settings_summary' => [],
+      'settings_edit' => [],
+    ];
+
+    // Base button element for the various plugin settings actions.
+    $base_button = [
+      '#submit' => ['::multistepSubmit'],
+      '#ajax' => [
+        'callback' => '::multistepAjax',
+        'wrapper' => 'field-display-overview-wrapper',
+        'effect' => 'fade',
+      ],
+      '#field_name' => $block_name,
+    ];
+
+    if ($form_state->get('plugin_settings_edit') == $block_name) {
+      // Generate the settings form and allow other modules to alter it.
+      $block_field_row['plugin']['#cell_attributes'] = ['colspan' => 3];
+      $block_field_row['plugin']['settings_edit_form'] = [
+        '#type' => 'container',
+        '#attributes' => ['class' => ['field-plugin-settings-edit-form']],
+        '#parents' => ['fields', $block_name, 'settings_edit_form'],
+        'settings' => [],
+        'actions' => [
+          '#type' => 'actions',
+          'save_settings' => $base_button + [
+            '#type' => 'submit',
+            '#button_type' => 'primary',
+            '#name' => $block_name . '_plugin_settings_update',
+            '#value' => $this->t('Update'),
+            '#op' => 'update',
+          ],
+          'cancel_settings' => $base_button + [
+            '#type' => 'submit',
+            '#name' => $block_name . '_plugin_settings_cancel',
+            '#value' => $this->t('Cancel'),
+            '#op' => 'cancel',
+            // Do not check errors for the 'Cancel' button, but make sure we
+            // get the value of the 'plugin type' select.
+            '#limit_validation_errors' => [['fields', $block_name, 'type']],
+          ],
+          'remove_settings' => $base_button + [
+            '#type' => 'submit',
+            '#button_type' => 'danger',
+            '#name' => $block_name . '_plugin_settings_remove',
+            '#value' => $this->t('Remove'),
+            '#op' => 'remove',
+            // Do not check errors for the 'Remove' button.
+            '#limit_validation_errors' => [],
+          ],
+        ],
+      ];
+      $block_field_row['#attributes']['class'][] = 'field-plugin-settings-editing';
+      $subform_state = SubformState::createForSubform($block_field_row['plugin']['settings_edit_form']['settings'], $form, $form_state);
+      $block_field_row['plugin']['settings_edit_form']['settings'] = $block->buildConfigurationForm($block_field_row['plugin']['settings_edit_form']['settings'], $subform_state);
+    }
+    else {
+      // Check selected plugin settings to display edit link or not.
+      $block_field_row['settings_edit'] = $base_button + [
+        '#type' => 'image_button',
+        '#name' => $block_name . '_settings_edit',
+        '#src' => 'core/misc/icons/787878/cog.svg',
+        '#attributes' => ['class' => ['field-plugin-settings-edit'], 'alt' => $this->t('Edit')],
+        '#op' => 'edit',
+        // Do not check errors for the 'Edit' button, but make sure we get
+        // the value of the 'plugin type' select.
+        '#limit_validation_errors' => [['fields', $block_name, 'type']],
+        '#prefix' => '<div class="field-plugin-settings-edit-wrapper">',
+        '#suffix' => '</div>',
+      ];
+    }
+
+    return $block_field_row;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function copyFormValuesToEntity(EntityInterface $entity, array $form, FormStateInterface $form_state) {
+    /** @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface $entity */
+    parent::copyFormValuesToEntity($entity, $form, $form_state);
+
+    $block_manager = \Drupal::service('plugin.manager.block');
+    foreach ($entity->getBlocks() as $name => $block_info) {
+      $form_values = $form_state->getValue(['fields', $name]);
+      if ($form_state->get('plugin_settings_remove') === $name) {
+        $form_state->set('plugin_settings_remove', NULL);
+        $entity->removeBlock($name);
+      }
+      else {
+        if ($form_state->get('plugin_settings_update') === $name) {
+          $form_state->set('plugin_settings_update', NULL);
+
+          $block = $block_manager->createInstance($block_info['plugin_id'], $block_info['settings']);
+
+          $sub_form_state = SubformState::createForSubform($form['fields'][$name]['plugin']['settings_edit_form']['settings'], $form, $form_state);
+          $block->submitConfigurationForm($form, $sub_form_state);
+
+          if ($block instanceof ContextAwarePluginInterface && $block->getContextDefinitions()) {
+            $context_mapping = $sub_form_state->getValue('context_mapping', []);
+            $block->setContextMapping($context_mapping);
+          }
+
+          $block_info['settings'] = $block->getConfiguration();
+        }
+        $block_info['weight'] = $form_values['weight'];
+        $block_info['region'] = $form_values['region'];
+        $entity->setBlock($name, $block_info);
+      }
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function multistepSubmit($form, FormStateInterface $form_state) {
+    $trigger = $form_state->getTriggeringElement();
+    if ($trigger['#op'] == 'remove') {
+      // Set the field back to 'non edit' mode, and update $this->entity with
+      // the new settings fro the next rebuild.
+      $field_name = $trigger['#field_name'];
+      $form_state->set('plugin_settings_edit', NULL);
+      $form_state->set('plugin_settings_remove', $field_name);
+      $this->entity = $this->buildEntity($form, $form_state);
+      $form_state->setRebuild();
+    }
+    else {
+      parent::multistepSubmit($form, $form_state);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   protected function getEntityDisplay($entity_type_id, $bundle, $mode) {
     return entity_get_display($entity_type_id, $bundle, $mode);
   }
diff --git a/core/modules/field_ui/src/Routing/RouteSubscriber.php b/core/modules/field_ui/src/Routing/RouteSubscriber.php
index b08e7f8..0f9a66b 100644
--- a/core/modules/field_ui/src/Routing/RouteSubscriber.php
+++ b/core/modules/field_ui/src/Routing/RouteSubscriber.php
@@ -154,6 +154,17 @@ protected function alterRoutes(RouteCollection $collection) {
           $options
         );
         $collection->add("entity.entity_view_display.{$entity_type_id}.view_mode", $route);
+
+        $route = new Route(
+          "$path/display/{view_mode_name}/add-block",
+          [
+            '_entity_form' => 'entity_view_display.add_block',
+            '_title' => 'Add block',
+          ] + $defaults,
+          ['_field_ui_view_mode_access' => 'administer ' . $entity_type_id . ' display'],
+          $options
+        );
+        $collection->add("entity.entity_view_display.{$entity_type_id}.add_block", $route);
       }
     }
   }
diff --git a/core/modules/field_ui/tests/src/FunctionalJavascript/EntityDisplayTest.php b/core/modules/field_ui/tests/src/FunctionalJavascript/EntityDisplayTest.php
index 6da3c41..2c15103 100644
--- a/core/modules/field_ui/tests/src/FunctionalJavascript/EntityDisplayTest.php
+++ b/core/modules/field_ui/tests/src/FunctionalJavascript/EntityDisplayTest.php
@@ -15,7 +15,12 @@ class EntityDisplayTest extends JavascriptTestBase {
   /**
    * {@inheritdoc}
    */
-  public static $modules = ['field_ui', 'entity_test'];
+  public static $modules = ['field_ui', 'entity_test', 'block_test'];
+
+  /**
+   * @var \Drupal\Core\Session\AccountInterface
+   */
+  protected $user;
 
   /**
    * {@inheritdoc}
@@ -30,7 +35,7 @@ protected function setUp() {
       ]],
     ]);
     $entity->save();
-    $this->drupalLogin($this->drupalCreateUser([
+    $this->user = $this->drupalCreateUser([
       'access administration pages',
       'view test entity',
       'administer entity_test content',
@@ -38,7 +43,8 @@ protected function setUp() {
       'administer entity_test display',
       'administer entity_test form display',
       'view the administration theme',
-    ]));
+    ]);
+    $this->drupalLogin($this->user);
   }
 
   /**
@@ -87,6 +93,88 @@ public function testEntityView() {
   }
 
   /**
+   * Tests that blocks can be added to entity view displays.
+   */
+  public function testEntityViewWithBlocks() {
+    $assert_session = $this->assertSession();
+    $page = $this->getSession()->getPage();
+
+    $this->drupalGet('entity_test/structure/entity_test/display');
+    $this->clickLink('Add field block');
+    $assert_session->assertWaitOnAjaxRequest();
+    // Ensure that blocks with unsatisfiable contexts are not shown.
+    $assert_session->pageTextNotContains('Test context-aware unsatisfied block');
+    // Ensure that context-aware blocks are shown.
+    $assert_session->pageTextContains('Test context-aware block');
+
+    // Set the context-aware to visible, but do not assign a context mapping.
+    $page->checkField('blocks[test_context_aware]');
+    $page->find('css', '.ui-dialog-buttonpane .button--primary')->press();
+    $assert_session->pageTextContains('Your settings have been saved.');
+
+    $this->drupalGet('entity_test/1');
+    $assert_session->pageTextContains('No context mapping selected.');
+
+    // Set the context mapping.
+    $this->drupalGet('entity_test/structure/entity_test/display');
+    $this->click('[name=testcontextawareblock_settings_edit]');
+    $assert_session->assertWaitOnAjaxRequest();
+    $page->selectFieldOption('fields[testcontextawareblock][settings_edit_form][settings][context_mapping][user]', '@user.current_user_context:current_user');
+    $this->submitForm([], 'Update');
+    $assert_session->assertWaitOnAjaxRequest();
+    $this->submitForm([], 'Save');
+    $assert_session->pageTextContains('Your settings have been saved.');
+
+    $this->drupalGet('entity_test/1');
+    $assert_session->pageTextNotContains('No context mapping selected');
+    $assert_session->pageTextContains($this->user->getAccountName());
+
+    // Add another instance of the same block.
+    $this->drupalGet('entity_test/structure/entity_test/display');
+    $this->clickLink('Add field block');
+    $assert_session->assertWaitOnAjaxRequest();
+    $page->checkField('blocks[test_context_aware]');
+    $page->find('css', '.ui-dialog-buttonpane .button--primary')->press();
+    $assert_session->pageTextContains('Your settings have been saved.');
+
+    $this->drupalGet('entity_test/1');
+    $assert_session->pageTextContains('No context mapping selected');
+    $assert_session->pageTextContains($this->user->getAccountName());
+
+    // Disable the field by dragging.
+    $this->drupalGet('entity_test/structure/entity_test/display');
+    $block_field_row = $page->find('css', '#testcontextawareblock-2');
+    $disabled_region_row = $page->find('css', '.region-hidden-title');
+    $block_field_row->find('css', '.handle')->dragTo($disabled_region_row);
+    $assert_session->assertWaitOnAjaxRequest();
+    $this->submitForm([], 'Save');
+    $this->assertSame('hidden', $assert_session->selectExists('fields[testcontextawareblock_2][region]')->getValue());
+    $assert_session->pageTextContains('Your settings have been saved.');
+
+    $this->drupalGet('entity_test/1');
+    $assert_session->pageTextNotContains('No context mapping selected');
+    $assert_session->pageTextContains($this->user->getAccountName());
+
+    // Remove the blocks.
+    $this->drupalGet('entity_test/structure/entity_test/display');
+    $this->click('[name=testcontextawareblock_settings_edit]');
+    $assert_session->assertWaitOnAjaxRequest();
+    $page->pressButton('Remove');
+    $assert_session->assertWaitOnAjaxRequest();
+    $this->click('[name=testcontextawareblock_2_settings_edit]');
+    $assert_session->assertWaitOnAjaxRequest();
+    $page->pressButton('Remove');
+    $assert_session->assertWaitOnAjaxRequest();
+    $this->submitForm([], 'Save');
+    $assert_session->pageTextNotContains('Test context-aware block');
+    $assert_session->pageTextContains('Your settings have been saved.');
+
+    $this->drupalGet('entity_test/1');
+    $assert_session->pageTextNotContains('No context mapping selected');
+    $assert_session->pageTextNotContains($this->user->getAccountName());
+  }
+
+  /**
    * Tests extra fields.
    */
   public function testExtraFields() {
diff --git a/core/modules/forum/config/optional/core.entity_view_display.comment.comment_forum.default.yml b/core/modules/forum/config/optional/core.entity_view_display.comment.comment_forum.default.yml
index befeba8..b1d2d79 100644
--- a/core/modules/forum/config/optional/core.entity_view_display.comment.comment_forum.default.yml
+++ b/core/modules/forum/config/optional/core.entity_view_display.comment.comment_forum.default.yml
@@ -21,4 +21,5 @@ content:
   links:
     weight: 100
     region: content
+blocks: {  }
 hidden: {  }
diff --git a/core/modules/forum/config/optional/core.entity_view_display.node.forum.default.yml b/core/modules/forum/config/optional/core.entity_view_display.node.forum.default.yml
index f3e8c5c..fc36c27 100644
--- a/core/modules/forum/config/optional/core.entity_view_display.node.forum.default.yml
+++ b/core/modules/forum/config/optional/core.entity_view_display.node.forum.default.yml
@@ -43,4 +43,5 @@ content:
     settings:
       link: true
     third_party_settings: {  }
+blocks: {  }
 hidden: {  }
diff --git a/core/modules/forum/config/optional/core.entity_view_display.node.forum.teaser.yml b/core/modules/forum/config/optional/core.entity_view_display.node.forum.teaser.yml
index 7b174f4..0ba658f 100644
--- a/core/modules/forum/config/optional/core.entity_view_display.node.forum.teaser.yml
+++ b/core/modules/forum/config/optional/core.entity_view_display.node.forum.teaser.yml
@@ -34,5 +34,6 @@ content:
     settings:
       link: true
     third_party_settings: {  }
+blocks: {  }
 hidden:
   comment_forum: true
diff --git a/core/modules/forum/config/optional/core.entity_view_display.taxonomy_term.forums.default.yml b/core/modules/forum/config/optional/core.entity_view_display.taxonomy_term.forums.default.yml
index b326039..14ef792 100644
--- a/core/modules/forum/config/optional/core.entity_view_display.taxonomy_term.forums.default.yml
+++ b/core/modules/forum/config/optional/core.entity_view_display.taxonomy_term.forums.default.yml
@@ -18,5 +18,6 @@ content:
     settings: {  }
     third_party_settings: {  }
     label: above
+blocks: {  }
 hidden:
   forum_container: true
diff --git a/core/modules/options/tests/options_config_install_test/config/install/core.entity_view_display.node.options_install_test.default.yml b/core/modules/options/tests/options_config_install_test/config/install/core.entity_view_display.node.options_install_test.default.yml
index aaea1cb..bcec50d 100644
--- a/core/modules/options/tests/options_config_install_test/config/install/core.entity_view_display.node.options_install_test.default.yml
+++ b/core/modules/options/tests/options_config_install_test/config/install/core.entity_view_display.node.options_install_test.default.yml
@@ -22,6 +22,7 @@ content:
     region: content
     settings: {  }
     third_party_settings: {  }
+blocks: {  }
 hidden:
   langcode: true
 third_party_settings: {  }
diff --git a/core/modules/options/tests/options_config_install_test/config/install/core.entity_view_display.node.options_install_test.teaser.yml b/core/modules/options/tests/options_config_install_test/config/install/core.entity_view_display.node.options_install_test.teaser.yml
index 6e79af9..6e27348 100644
--- a/core/modules/options/tests/options_config_install_test/config/install/core.entity_view_display.node.options_install_test.teaser.yml
+++ b/core/modules/options/tests/options_config_install_test/config/install/core.entity_view_display.node.options_install_test.teaser.yml
@@ -24,6 +24,7 @@ content:
     settings:
       trim_length: 600
     third_party_settings: {  }
+blocks: {  }
 hidden:
   langcode: true
 third_party_settings: {  }
diff --git a/core/profiles/standard/config/install/core.entity_view_display.block_content.basic.default.yml b/core/profiles/standard/config/install/core.entity_view_display.block_content.basic.default.yml
index e494882..603df4e 100644
--- a/core/profiles/standard/config/install/core.entity_view_display.block_content.basic.default.yml
+++ b/core/profiles/standard/config/install/core.entity_view_display.block_content.basic.default.yml
@@ -18,4 +18,5 @@ content:
     region: content
     settings: {  }
     third_party_settings: {  }
+blocks: {  }
 hidden: {  }
diff --git a/core/profiles/standard/config/install/core.entity_view_display.comment.comment.default.yml b/core/profiles/standard/config/install/core.entity_view_display.comment.comment.default.yml
index 6ae213d..32a6969 100644
--- a/core/profiles/standard/config/install/core.entity_view_display.comment.comment.default.yml
+++ b/core/profiles/standard/config/install/core.entity_view_display.comment.comment.default.yml
@@ -21,4 +21,5 @@ content:
   links:
     weight: 100
     region: content
+blocks: {  }
 hidden: {  }
diff --git a/core/profiles/standard/config/install/core.entity_view_display.node.article.default.yml b/core/profiles/standard/config/install/core.entity_view_display.node.article.default.yml
index 5c43252..f20f87b 100644
--- a/core/profiles/standard/config/install/core.entity_view_display.node.article.default.yml
+++ b/core/profiles/standard/config/install/core.entity_view_display.node.article.default.yml
@@ -55,6 +55,7 @@ content:
   links:
     weight: 100
     region: content
+blocks: {  }
 hidden:
   field_image: true
   field_tags: true
diff --git a/core/profiles/standard/config/install/core.entity_view_display.node.article.rss.yml b/core/profiles/standard/config/install/core.entity_view_display.node.article.rss.yml
index 84660b6..e972f68 100644
--- a/core/profiles/standard/config/install/core.entity_view_display.node.article.rss.yml
+++ b/core/profiles/standard/config/install/core.entity_view_display.node.article.rss.yml
@@ -18,6 +18,7 @@ content:
   links:
     weight: 100
     region: content
+blocks: {  }
 hidden:
   body: true
   comment: true
diff --git a/core/profiles/standard/config/install/core.entity_view_display.node.article.teaser.yml b/core/profiles/standard/config/install/core.entity_view_display.node.article.teaser.yml
index 7b96908..3d60011 100644
--- a/core/profiles/standard/config/install/core.entity_view_display.node.article.teaser.yml
+++ b/core/profiles/standard/config/install/core.entity_view_display.node.article.teaser.yml
@@ -46,6 +46,7 @@ content:
   links:
     weight: 100
     region: content
+blocks: {  }
 hidden:
   comment: true
   field_image: true
diff --git a/core/profiles/standard/config/install/core.entity_view_display.node.page.default.yml b/core/profiles/standard/config/install/core.entity_view_display.node.page.default.yml
index 8afd942..cb23010 100644
--- a/core/profiles/standard/config/install/core.entity_view_display.node.page.default.yml
+++ b/core/profiles/standard/config/install/core.entity_view_display.node.page.default.yml
@@ -22,4 +22,5 @@ content:
   links:
     weight: 101
     region: content
+blocks: {  }
 hidden: {  }
diff --git a/core/profiles/standard/config/install/core.entity_view_display.node.page.teaser.yml b/core/profiles/standard/config/install/core.entity_view_display.node.page.teaser.yml
index bc7a68c..e646d7a 100644
--- a/core/profiles/standard/config/install/core.entity_view_display.node.page.teaser.yml
+++ b/core/profiles/standard/config/install/core.entity_view_display.node.page.teaser.yml
@@ -24,4 +24,5 @@ content:
   links:
     weight: 101
     region: content
+blocks: {  }
 hidden: {  }
diff --git a/core/profiles/standard/config/install/core.entity_view_display.user.user.compact.yml b/core/profiles/standard/config/install/core.entity_view_display.user.user.compact.yml
index 2ff13ad..f5097d3 100644
--- a/core/profiles/standard/config/install/core.entity_view_display.user.user.compact.yml
+++ b/core/profiles/standard/config/install/core.entity_view_display.user.user.compact.yml
@@ -22,5 +22,6 @@ content:
       image_link: content
     third_party_settings: {  }
     label: hidden
+blocks: {  }
 hidden:
   member_for: true
diff --git a/core/profiles/standard/config/install/core.entity_view_display.user.user.default.yml b/core/profiles/standard/config/install/core.entity_view_display.user.user.default.yml
index ef1fdd7..5036faf 100644
--- a/core/profiles/standard/config/install/core.entity_view_display.user.user.default.yml
+++ b/core/profiles/standard/config/install/core.entity_view_display.user.user.default.yml
@@ -24,4 +24,5 @@ content:
       image_link: content
     third_party_settings: {  }
     label: hidden
+blocks: {  }
 hidden: {  }
diff --git a/core/tests/Drupal/KernelTests/Core/Entity/EntityDisplayFormBaseTest.php b/core/tests/Drupal/KernelTests/Core/Entity/EntityDisplayFormBaseTest.php
index 11aeede..179062b 100644
--- a/core/tests/Drupal/KernelTests/Core/Entity/EntityDisplayFormBaseTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Entity/EntityDisplayFormBaseTest.php
@@ -2,7 +2,7 @@
 
 namespace Drupal\KernelTests\Core\Entity;
 
-use Drupal\Core\Entity\Display\EntityDisplayInterface;
+use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
 use Drupal\Core\Form\FormState;
 use Drupal\field_ui\Form\EntityViewDisplayEditForm;
 use Drupal\KernelTests\KernelTestBase;
@@ -24,8 +24,10 @@ class EntityDisplayFormBaseTest extends KernelTestBase {
    */
   public function testCopyFormValuesToEntity() {
     $field_values = [];
-    $entity = $this->prophesize(EntityDisplayInterface::class);
+    $entity = $this->prophesize(EntityViewDisplayInterface::class);
     $entity->getPluginCollections()->willReturn([]);
+    // @todo.
+    $entity->getBlocks()->willReturn([]);
     $entity->getTargetEntityTypeId()->willReturn('entity_test_with_bundle');
     $entity->getTargetBundle()->willReturn('target_bundle');
 
