diff --git a/core/lib/Drupal/Core/Annotation/ContextDefinition.php b/core/lib/Drupal/Core/Annotation/ContextDefinition.php
index e820f0c..c1bb0e9 100644
--- a/core/lib/Drupal/Core/Annotation/ContextDefinition.php
+++ b/core/lib/Drupal/Core/Annotation/ContextDefinition.php
@@ -113,7 +113,7 @@ public function __construct(array $values) {
     // used in the classes they pass to.
     foreach (['label', 'description'] as $key) {
       // @todo Remove this workaround in https://www.drupal.org/node/2362727.
-      if (isset($values[$key]) && $values[$key] instanceof TranslationWrapper) {
+      if (isset($values[$key]) && $values[$key] instanceof Translation && $values[$key]->get() instanceof TranslationWrapper) {
         $values[$key] = (string) $values[$key]->get();
       }
       else {
diff --git a/core/lib/Drupal/Core/Block/BlockBase.php b/core/lib/Drupal/Core/Block/BlockBase.php
index ef127e9..6665511 100644
--- a/core/lib/Drupal/Core/Block/BlockBase.php
+++ b/core/lib/Drupal/Core/Block/BlockBase.php
@@ -12,6 +12,7 @@
 use Drupal\Core\Access\AccessResult;
 use Drupal\Core\Cache\CacheableDependencyInterface;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Plugin\ContextAwarePluginAssignmentTrait;
 use Drupal\Core\Plugin\ContextAwarePluginBase;
 use Drupal\Component\Utility\Unicode;
 use Drupal\Component\Utility\NestedArray;
@@ -31,6 +32,8 @@
  */
 abstract class BlockBase extends ContextAwarePluginBase implements BlockPluginInterface {
 
+  use ContextAwarePluginAssignmentTrait;
+
   /**
    * The transliteration service.
    *
@@ -199,6 +202,9 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta
       '#options' => $period,
     );
 
+    // Add context form elements.
+    $contexts = $form_state->getTemporaryValue('gathered_contexts') ?: [];
+    $form['context_mapping'] = $this->addContextAssignmentElement($this, $contexts);
     // Add plugin-specific settings for this block type.
     $form += $this->blockForm($form, $form_state);
     return $form;
diff --git a/core/lib/Drupal/Core/Plugin/ContextAwarePluginAssignmentTrait.php b/core/lib/Drupal/Core/Plugin/ContextAwarePluginAssignmentTrait.php
index 19d756c..e3ae261 100644
--- a/core/lib/Drupal/Core/Plugin/ContextAwarePluginAssignmentTrait.php
+++ b/core/lib/Drupal/Core/Plugin/ContextAwarePluginAssignmentTrait.php
@@ -51,16 +51,26 @@ protected function addContextAssignmentElement(ContextAwarePluginInterface $plug
           '#type' => 'value',
           '#value' => $context_id,
         ];
+        $element['context_slot_title'] = [
+          '#type' => 'item',
+          '#title' => $definition->getLabel() ?: $context_slot,
+          '#markup' => $options[$context_id],
+        ];
       }
 
       if (count($options) > 1) {
+        // The context display element is only useful when a single context is
+        // available, we have multiple and require user interaction.
+        unset($element['context_slot_title']);
+
         $assignments = $plugin->getContextMapping();
         $element[$context_slot] = [
-          '#title' => $this->t('Select a @context value:', ['@context' => $context_slot]),
+          '#title' => $definition->getLabel() ?: $context_slot,
           '#type' => 'select',
           '#options' => $options,
           '#required' => $definition->isRequired(),
           '#default_value' => !empty($assignments[$context_slot]) ? $assignments[$context_slot] : '',
+          '#description' => $definition->getDescription(),
         ];
       }
     }
diff --git a/core/lib/Drupal/Core/Plugin/ContextAwarePluginBase.php b/core/lib/Drupal/Core/Plugin/ContextAwarePluginBase.php
index 51a39d7..a5154d5 100644
--- a/core/lib/Drupal/Core/Plugin/ContextAwarePluginBase.php
+++ b/core/lib/Drupal/Core/Plugin/ContextAwarePluginBase.php
@@ -64,6 +64,10 @@ public function getContextMapping() {
    * {@inheritdoc}
    */
   public function setContextMapping(array $context_mapping) {
+    // The ContextAwarePluginAssignmentTrait adds a visual element to the
+    // context mapping when only one context is available. We should unset this
+    // before saving the context mapping.
+    unset($context_mapping['context_slot_title']);
     if ($this instanceof ConfigurablePluginInterface) {
       $configuration = $this->getConfiguration();
       $configuration['context_mapping'] = $context_mapping;
diff --git a/core/modules/aggregator/aggregator.services.yml b/core/modules/aggregator/aggregator.services.yml
index 6b191c8..3c55a3f 100644
--- a/core/modules/aggregator/aggregator.services.yml
+++ b/core/modules/aggregator/aggregator.services.yml
@@ -14,3 +14,8 @@ services:
   logger.channel.aggregator:
     parent: logger.channel_base
     arguments: ['aggregator']
+  aggregator.feed_context:
+    class: Drupal\aggregator\EventSubscriber\AggregatorFeedContext
+    arguments: ['@entity.manager', '@theme.manager']
+    tags:
+      - { name: context_provider }
diff --git a/core/modules/aggregator/config/schema/aggregator.schema.yml b/core/modules/aggregator/config/schema/aggregator.schema.yml
index eb6c006..7b31e16 100644
--- a/core/modules/aggregator/config/schema/aggregator.schema.yml
+++ b/core/modules/aggregator/config/schema/aggregator.schema.yml
@@ -44,9 +44,14 @@ block.settings.aggregator_feed_block:
     block_count:
       type: integer
       label: 'Block count'
-    feed:
-      type: string
-      label: 'Feed'
+    context_mapping:
+      type: mapping
+      label: 'Context assignments'
+      mapping:
+        # This will be stored in the format of 'aggregator.feed:$uuid'.
+        feed:
+          type: string
+          label: 'Feed'
 
 field.formatter.settings.aggregator_title:
   type: mapping
diff --git a/core/modules/aggregator/src/Entity/Feed.php b/core/modules/aggregator/src/Entity/Feed.php
index a5ed081..6c964db 100644
--- a/core/modules/aggregator/src/Entity/Feed.php
+++ b/core/modules/aggregator/src/Entity/Feed.php
@@ -115,9 +115,13 @@ public static function postDelete(EntityStorageInterface $storage, array $entiti
     parent::postDelete($storage, $entities);
     if (\Drupal::moduleHandler()->moduleExists('block')) {
       // Make sure there are no active blocks for these feeds.
+      $context_ids = [];
+      foreach ($entities as $key => $entity) {
+        $context_ids[$key] = '@aggregator.feed_context:' . $entity->uuid();
+      }
       $ids = \Drupal::entityQuery('block')
         ->condition('plugin', 'aggregator_feed_block')
-        ->condition('settings.feed', array_keys($entities))
+        ->condition('settings.context_mapping.feed', $context_ids)
         ->execute();
       if ($ids) {
         $block_storage = \Drupal::entityManager()->getStorage('block');
diff --git a/core/modules/aggregator/src/EventSubscriber/AggregatorFeedContext.php b/core/modules/aggregator/src/EventSubscriber/AggregatorFeedContext.php
new file mode 100644
index 0000000..5dfcd58
--- /dev/null
+++ b/core/modules/aggregator/src/EventSubscriber/AggregatorFeedContext.php
@@ -0,0 +1,78 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\aggregator\EventSubscriber\AggregatorFeedContext.
+ */
+
+namespace Drupal\aggregator\EventSubscriber;
+
+use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Plugin\Context\Context;
+use Drupal\Core\Plugin\Context\ContextDefinition;
+use Drupal\Core\Plugin\Context\ContextProviderInterface;
+use Drupal\Core\Theme\ThemeManagerInterface;
+
+/**
+ * Provides aggregator feeds as context.
+ */
+class AggregatorFeedContext implements ContextProviderInterface {
+
+  /**
+   * The entity storage for feeds.
+   *
+   * @var \Drupal\aggregator\FeedStorageInterface
+   */
+  protected $feedStorage;
+
+  /**
+   * The theme manager.
+   *
+   * @var \Drupal\Core\Theme\ThemeManagerInterface
+   */
+  protected $themeManager;
+
+  /**
+   * Constructs a new AggregatorFeedContext.
+   *
+   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
+   *   The entity manager.
+   * @param \Drupal\Core\Theme\ThemeManagerInterface $theme_manager
+   *   The theme manager.
+   */
+  public function __construct(EntityManagerInterface $entity_manager, ThemeManagerInterface $theme_manager) {
+    $this->feedStorage = $entity_manager->getStorage('aggregator_feed');
+    $this->themeManager = $theme_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getRuntimeContexts(array $unqualified_context_ids) {
+    $ids = $this->feedStorage->getQuery()
+      ->condition('uuid', $unqualified_context_ids, 'IN')
+      ->execute();
+    $contexts = [];
+    foreach ($this->feedStorage->loadMultiple($ids) as $feed) {
+      $context = new Context(new ContextDefinition('entity:aggregator_feed'));
+      $context->setContextValue($feed);
+      $contexts[$feed->uuid()] = $context;
+    }
+    return $contexts;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getAvailableContexts() {
+    $feeds = $this->feedStorage->loadMultiple();
+    $contexts = [];
+    foreach ($feeds as $feed) {
+      $context = new Context(new ContextDefinition('entity:aggregator_feed', $feed->label()));
+      $context->setContextValue($feed);
+      $contexts[$feed->uuid()] = $context;
+    }
+    return $contexts;
+  }
+
+}
diff --git a/core/modules/aggregator/src/Plugin/Block/AggregatorFeedBlock.php b/core/modules/aggregator/src/Plugin/Block/AggregatorFeedBlock.php
index ec424a9..a784011 100644
--- a/core/modules/aggregator/src/Plugin/Block/AggregatorFeedBlock.php
+++ b/core/modules/aggregator/src/Plugin/Block/AggregatorFeedBlock.php
@@ -7,11 +7,9 @@
 
 namespace Drupal\aggregator\Plugin\Block;
 
-use Drupal\aggregator\FeedStorageInterface;
 use Drupal\aggregator\ItemStorageInterface;
 use Drupal\Core\Access\AccessResult;
 use Drupal\Core\Block\BlockBase;
-use Drupal\Core\Cache\Cache;
 use Drupal\Core\Entity\Query\QueryInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
@@ -24,19 +22,16 @@
  * @Block(
  *   id = "aggregator_feed_block",
  *   admin_label = @Translation("Aggregator feed"),
- *   category = @Translation("Lists (Views)")
+ *   category = @Translation("Lists (Views)"),
+ *   context = {
+ *     "feed" = @ContextDefinition("entity:aggregator_feed", label = @Translation("Aggregator feed"), description = @Translation("Select the feed that should be displayed"))
+ *   }
  * )
+ *
  */
 class AggregatorFeedBlock extends BlockBase implements ContainerFactoryPluginInterface {
 
   /**
-   * The entity storage for feeds.
-   *
-   * @var \Drupal\aggregator\FeedStorageInterface
-   */
-  protected $feedStorage;
-
-  /**
    * The entity storage for items.
    *
    * @var \Drupal\aggregator\ItemStorageInterface
@@ -59,16 +54,13 @@ class AggregatorFeedBlock extends BlockBase implements ContainerFactoryPluginInt
    *   The plugin_id for the plugin instance.
    * @param mixed $plugin_definition
    *   The plugin implementation definition.
-   * @param \Drupal\aggregator\FeedStorageInterface $feed_storage
-   *   The entity storage for feeds.
    * @param \Drupal\aggregator\ItemStorageInterface $item_storage
    *   The entity storage for feed items.
    * @param \Drupal\Core\Entity\Query\QueryInterface $item_query
    *   The entity query object for feed items.
    */
-  public function __construct(array $configuration, $plugin_id, $plugin_definition, FeedStorageInterface $feed_storage, ItemStorageInterface $item_storage, QueryInterface $item_query) {
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, ItemStorageInterface $item_storage, QueryInterface $item_query) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);
-    $this->feedStorage = $feed_storage;
     $this->itemStorage = $item_storage;
     $this->itemQuery = $item_query;
   }
@@ -82,7 +74,6 @@ public static function create(ContainerInterface $container, array $configuratio
       $configuration,
       $plugin_id,
       $plugin_definition,
-      $container->get('entity.manager')->getStorage('aggregator_feed'),
       $container->get('entity.manager')->getStorage('aggregator_item'),
       $container->get('entity.query')->get('aggregator_item')
     );
@@ -96,7 +87,6 @@ public function defaultConfiguration() {
     // By default, the block will contain 10 feed items.
     return array(
       'block_count' => 10,
-      'feed' => NULL,
     );
   }
 
@@ -112,17 +102,6 @@ protected function blockAccess(AccountInterface $account) {
    * {@inheritdoc}
    */
   public function blockForm($form, FormStateInterface $form_state) {
-    $feeds = $this->feedStorage->loadMultiple();
-    $options = array();
-    foreach ($feeds as $feed) {
-      $options[$feed->id()] = $feed->label();
-    }
-    $form['feed'] = array(
-      '#type' => 'select',
-      '#title' => $this->t('Select the feed that should be displayed'),
-      '#default_value' => $this->configuration['feed'],
-      '#options' => $options,
-    );
     $range = range(2, 20);
     $form['block_count'] = array(
       '#type' => 'select',
@@ -138,7 +117,6 @@ public function blockForm($form, FormStateInterface $form_state) {
    */
   public function blockSubmit($form, FormStateInterface $form_state) {
     $this->configuration['block_count'] = $form_state->getValue('block_count');
-    $this->configuration['feed'] = $form_state->getValue('feed');
   }
 
   /**
@@ -146,7 +124,7 @@ public function blockSubmit($form, FormStateInterface $form_state) {
    */
   public function build() {
     // Load the selected feed.
-    if ($feed = $this->feedStorage->load($this->configuration['feed'])) {
+    if ($feed = $this->getContextValue('feed')) {
       $result = $this->itemQuery
         ->condition('fid', $feed->id())
         ->range(0, $this->configuration['block_count'])
@@ -179,13 +157,4 @@ public function build() {
     }
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function getCacheTags() {
-    $cache_tags = parent::getCacheTags();
-    $feed = $this->feedStorage->load($this->configuration['feed']);
-    return Cache::mergeTags($cache_tags, $feed->getCacheTags());
-  }
-
 }
diff --git a/core/modules/aggregator/src/Tests/AggregatorRenderingTest.php b/core/modules/aggregator/src/Tests/AggregatorRenderingTest.php
index 351f48c..14d28ea 100644
--- a/core/modules/aggregator/src/Tests/AggregatorRenderingTest.php
+++ b/core/modules/aggregator/src/Tests/AggregatorRenderingTest.php
@@ -44,7 +44,7 @@ public function testBlockLinks() {
     $block = $this->drupalPlaceBlock("aggregator_feed_block", array('label' => 'feed-' . $feed->label()));
 
     // Configure the feed that should be displayed.
-    $block->getPlugin()->setConfigurationValue('feed', $feed->id());
+    $block->getPlugin()->setContextMapping(['feed' => '@aggregator.feed_context:' . $feed->uuid()]);
     $block->getPlugin()->setConfigurationValue('block_count', 2);
     $block->save();
 
diff --git a/core/modules/aggregator/src/Tests/DeleteFeedTest.php b/core/modules/aggregator/src/Tests/DeleteFeedTest.php
index 3020982..f40be04 100644
--- a/core/modules/aggregator/src/Tests/DeleteFeedTest.php
+++ b/core/modules/aggregator/src/Tests/DeleteFeedTest.php
@@ -30,10 +30,10 @@ public function testDeleteFeed() {
 
     // Place a block for both feeds.
     $block = $this->drupalPlaceBlock('aggregator_feed_block');
-    $block->getPlugin()->setConfigurationValue('feed', $feed1->id());
+    $block->getPlugin()->setContextMapping(['feed' => '@aggregator.feed_context:' . $feed1->uuid()]);
     $block->save();
     $block2 = $this->drupalPlaceBlock('aggregator_feed_block');
-    $block2->getPlugin()->setConfigurationValue('feed', $feed2->id());
+    $block2->getPlugin()->setContextMapping(['feed' => '@aggregator.feed_context:' . $feed2->uuid()]);
     $block2->save();
 
     // Delete feed.
diff --git a/core/modules/block/block.services.yml b/core/modules/block/block.services.yml
index fe20e4a..ff4277d 100644
--- a/core/modules/block/block.services.yml
+++ b/core/modules/block/block.services.yml
@@ -9,4 +9,4 @@ services:
       - { name: event_subscriber }
   block.repository:
     class: Drupal\block\BlockRepository
-    arguments: ['@entity.manager', '@theme.manager', '@context.handler']
+    arguments: ['@entity.manager', '@theme.manager', '@context.handler', '@context.repository']
diff --git a/core/modules/block/src/BlockForm.php b/core/modules/block/src/BlockForm.php
index 8c13bbb..e8035f4 100644
--- a/core/modules/block/src/BlockForm.php
+++ b/core/modules/block/src/BlockForm.php
@@ -334,7 +334,12 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
     $settings = (new FormState())->setValues($form_state->getValue('settings'));
 
     // Call the plugin submit handler.
-    $entity->getPlugin()->submitConfigurationForm($form, $settings);
+    $block = $entity->getPlugin();
+    $block->submitConfigurationForm($form, $settings);
+    if ($block instanceof ContextAwarePluginInterface && $block->getContextDefinitions()) {
+      $context_mapping = $settings->getValue('context_mapping', []);
+      $block->setContextMapping($context_mapping);
+    }
     // Update the original form values.
     $form_state->setValue('settings', $settings->getValues());
 
@@ -345,7 +350,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
       $condition_values = (new FormState())
         ->setValues($values);
       $condition->submitConfigurationForm($form, $condition_values);
-      if ($condition instanceof ContextAwarePluginInterface) {
+      if ($condition instanceof ContextAwarePluginInterface && $condition->getContextDefinitions()) {
         $context_mapping = isset($values['context_mapping']) ? $values['context_mapping'] : [];
         $condition->setContextMapping($context_mapping);
       }
diff --git a/core/modules/block/src/BlockListBuilder.php b/core/modules/block/src/BlockListBuilder.php
index 43d7a1c..18744e9 100644
--- a/core/modules/block/src/BlockListBuilder.php
+++ b/core/modules/block/src/BlockListBuilder.php
@@ -17,6 +17,7 @@
 use Drupal\Core\Form\FormBuilderInterface;
 use Drupal\Core\Form\FormInterface;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Plugin\Context\ContextRepositoryInterface;
 use Drupal\Core\Theme\ThemeManagerInterface;
 use Drupal\Core\Url;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -58,6 +59,13 @@ class BlockListBuilder extends ConfigEntityListBuilder implements FormInterface
   protected $formBuilder;
 
   /**
+   * The context repository.
+   *
+   * @var \Drupal\Core\Plugin\Context\ContextRepositoryInterface
+   */
+  protected $contextRepository;
+
+  /**
    * {@inheritdoc}
    */
   protected $limit = FALSE;
@@ -73,12 +81,15 @@ class BlockListBuilder extends ConfigEntityListBuilder implements FormInterface
    *   The theme manager.
    * @param \Drupal\Core\Form\FormBuilderInterface $form_builder
    *   The form builder.
+   * @param \Drupal\Core\Plugin\Context\ContextRepositoryInterface $context_repository
+   *   The context repository
    */
-  public function __construct(EntityTypeInterface $entity_type, EntityStorageInterface $storage, ThemeManagerInterface $theme_manager, FormBuilderInterface $form_builder) {
+  public function __construct(EntityTypeInterface $entity_type, EntityStorageInterface $storage, ThemeManagerInterface $theme_manager, FormBuilderInterface $form_builder, ContextRepositoryInterface $context_repository) {
     parent::__construct($entity_type, $storage);
 
     $this->themeManager = $theme_manager;
     $this->formBuilder = $form_builder;
+    $this->contextRepository = $context_repository;
   }
 
   /**
@@ -89,7 +100,8 @@ public static function createInstance(ContainerInterface $container, EntityTypeI
       $entity_type,
       $container->get('entity.manager')->getStorage($entity_type->id()),
       $container->get('theme.manager'),
-      $container->get('form_builder')
+      $container->get('form_builder'),
+      $container->get('context.repository')
     );
   }
 
@@ -309,6 +321,79 @@ protected function buildBlocksForm() {
   }
 
   /**
+   * Builds the "Place Blocks" portion of the form.
+   *
+   * @return array
+   */
+  protected function buildPlaceBlocksForm() {
+    $form['title'] = array(
+      '#type' => 'container',
+      '#markup' => '<h3>' . $this->t('Place blocks') . '</h3>',
+      '#attributes' => array(
+        'class' => array(
+          'entity-meta__header',
+        ),
+      ),
+    );
+
+    $form['filter'] = array(
+      '#type' => 'search',
+      '#title' => $this->t('Filter'),
+      '#title_display' => 'invisible',
+      '#size' => 30,
+      '#placeholder' => $this->t('Filter by block name'),
+      '#attributes' => array(
+        'class' => array('block-filter-text'),
+        'data-element' => '.entity-meta',
+        'title' => $this->t('Enter a part of the block name to filter by.'),
+      ),
+    );
+
+    $form['list']['#type'] = 'container';
+    $form['list']['#attributes']['class'][] = 'entity-meta';
+
+    // Only add blocks which work without any available context.
+    $contexts = $this->contextRepository->getAvailableContexts();
+    $definitions = $this->blockManager->getDefinitionsForContexts($contexts);
+    $sorted_definitions = $this->blockManager->getSortedDefinitions($definitions);
+    foreach ($sorted_definitions as $plugin_id => $plugin_definition) {
+      $category = SafeMarkup::checkPlain($plugin_definition['category']);
+      $category_key = 'category-' . $category;
+      if (!isset($form['list'][$category_key])) {
+        $form['list'][$category_key] = array(
+          '#type' => 'details',
+          '#title' => $category,
+          '#open' => TRUE,
+          'content' => array(
+            '#theme' => 'links',
+            '#links' => array(),
+            '#attributes' => array(
+              'class' => array(
+                'block-list',
+              ),
+            ),
+          ),
+        );
+      }
+      $form['list'][$category_key]['content']['#links'][$plugin_id] = array(
+        'title' => $plugin_definition['admin_label'],
+        'url' => Url::fromRoute('block.admin_add', [
+          'plugin_id' => $plugin_id,
+          'theme' => $this->theme
+        ]),
+        'attributes' => array(
+          'class' => array('use-ajax', 'block-filter-text-source'),
+          'data-dialog-type' => 'modal',
+          'data-dialog-options' => Json::encode(array(
+            'width' => 700,
+          )),
+        ),
+      );
+    }
+    return $form;
+  }
+
+  /**
    * Gets the name of the theme used for this block listing.
    *
    * @return string
diff --git a/core/modules/block/src/BlockRepository.php b/core/modules/block/src/BlockRepository.php
index 9d56fde..0b9afc8 100644
--- a/core/modules/block/src/BlockRepository.php
+++ b/core/modules/block/src/BlockRepository.php
@@ -10,6 +10,8 @@
 use Drupal\Core\Cache\CacheableMetadata;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Plugin\Context\ContextHandlerInterface;
+use Drupal\Core\Plugin\Context\ContextRepositoryInterface;
+use Drupal\Core\Plugin\ContextAwarePluginInterface;
 use Drupal\Core\Theme\ThemeManagerInterface;
 
 /**
@@ -32,6 +34,20 @@ class BlockRepository implements BlockRepositoryInterface {
   protected $themeManager;
 
   /**
+   * The context repository.
+   *
+   * @var \Drupal\Core\Plugin\Context\ContextRepositoryInterface
+   */
+  protected $contextRepository;
+
+  /**
+   * The context handler.
+   *
+   * @var \Drupal\Core\Plugin\Context\ContextHandlerInterface
+   */
+  protected $contextHandler;
+
+  /**
    * Constructs a new BlockRepository.
    *
    * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
@@ -40,11 +56,14 @@ class BlockRepository implements BlockRepositoryInterface {
    *   The theme manager.
    * @param \Drupal\Core\Plugin\Context\ContextHandlerInterface $context_handler
    *   The plugin context handler.
+   * @param \Drupal\Core\Plugin\Context\ContextRepositoryInterface $context_repository
+   *   The context repository
    */
-  public function __construct(EntityManagerInterface $entity_manager, ThemeManagerInterface $theme_manager, ContextHandlerInterface $context_handler) {
+  public function __construct(EntityManagerInterface $entity_manager, ThemeManagerInterface $theme_manager, ContextHandlerInterface $context_handler, ContextRepositoryInterface $context_repository) {
     $this->blockStorage = $entity_manager->getStorage('block');
     $this->themeManager = $theme_manager;
     $this->contextHandler = $context_handler;
+    $this->contextRepository = $context_repository;
   }
 
   /**
@@ -58,6 +77,13 @@ public function getVisibleBlocksPerRegion(array &$cacheable_metadata = []) {
     $full = array();
     foreach ($this->blockStorage->loadByProperties(array('theme' => $active_theme->getName())) as $block_id => $block) {
       /** @var \Drupal\block\BlockInterface $block */
+
+      $block_plugin = $block->getPlugin();
+      if ($block_plugin instanceof ContextAwarePluginInterface) {
+        $contexts = $this->contextRepository->getRuntimeContexts(array_values($block_plugin->getContextMapping()));
+        $this->contextHandler->applyContextMapping($block_plugin, $contexts);
+      }
+
       $access = $block->access('view', NULL, TRUE);
       $region = $block->getRegion();
       if (!isset($cacheable_metadata[$region])) {
diff --git a/core/modules/block/src/Controller/BlockLibraryController.php b/core/modules/block/src/Controller/BlockLibraryController.php
index 2a0148f..7aaab9d 100644
--- a/core/modules/block/src/Controller/BlockLibraryController.php
+++ b/core/modules/block/src/Controller/BlockLibraryController.php
@@ -13,6 +13,7 @@
 use Drupal\Core\Controller\ControllerBase;
 use Drupal\Core\EventSubscriber\MainContentViewSubscriber;
 use Drupal\Core\Menu\LocalActionManagerInterface;
+use Drupal\Core\Plugin\Context\LazyContextRepository;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Url;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -45,6 +46,13 @@ class BlockLibraryController extends ControllerBase {
   protected $localActionManager;
 
   /**
+   * The context repository.
+   *
+   * @var \Drupal\Core\Plugin\Context\LazyContextRepository
+   */
+  protected $contextRepository;
+
+  /**
    * Constructs a BlockLibraryController object.
    *
    * @param \Drupal\Core\Block\BlockManagerInterface $block_manager
@@ -54,10 +62,11 @@ class BlockLibraryController extends ControllerBase {
    * @param \Drupal\Core\Menu\LocalActionManagerInterface $local_action_manager
    *   The local action manager.
    */
-  public function __construct(BlockManagerInterface $block_manager, RouteMatchInterface $route_match, LocalActionManagerInterface $local_action_manager) {
+  public function __construct(BlockManagerInterface $block_manager, RouteMatchInterface $route_match, LocalActionManagerInterface $local_action_manager, LazyContextRepository $context_repository) {
     $this->blockManager = $block_manager;
     $this->routeMatch = $route_match;
     $this->localActionManager = $local_action_manager;
+    $this->contextRepository = $context_repository;
   }
 
   /**
@@ -67,7 +76,8 @@ public static function create(ContainerInterface $container) {
     return new static(
       $container->get('plugin.manager.block'),
       $container->get('current_route_match'),
-      $container->get('plugin.manager.menu.local_action')
+      $container->get('plugin.manager.menu.local_action'),
+      $container->get('context.repository')
     );
   }
 
@@ -96,7 +106,7 @@ public function listBlocks(Request $request, $theme) {
     ];
 
     // Only add blocks which work without any available context.
-    $definitions = $this->blockManager->getDefinitionsForContexts();
+    $definitions = $this->blockManager->getDefinitionsForContexts($this->contextRepository->getAvailableContexts());
     // Order by category, and then by admin label.
     $definitions = $this->blockManager->getSortedDefinitions($definitions);
 
diff --git a/core/modules/block/src/Tests/BlockInterfaceTest.php b/core/modules/block/src/Tests/BlockInterfaceTest.php
index 5e8b54c..adb3930 100644
--- a/core/modules/block/src/Tests/BlockInterfaceTest.php
+++ b/core/modules/block/src/Tests/BlockInterfaceTest.php
@@ -99,6 +99,7 @@ public function testBlockInterface() {
           '#options' => $period,
         ),
       ),
+      'context_mapping' => array(),
       'display_message' => array(
         '#type' => 'textfield',
         '#title' => t('Display message'),
diff --git a/core/modules/block/src/Tests/BlockUiTest.php b/core/modules/block/src/Tests/BlockUiTest.php
index 37fce6e..766303d 100644
--- a/core/modules/block/src/Tests/BlockUiTest.php
+++ b/core/modules/block/src/Tests/BlockUiTest.php
@@ -166,20 +166,41 @@ public function testCandidateBlockList() {
    */
   public function testContextAwareBlocks() {
     $arguments = array(
-      ':ul_class' => 'block-list',
-      ':li_class' => 'test-context-aware',
+      ':title' => 'Test context-aware block',
+      ':category' => 'Block test',
       ':href' => 'admin/structure/block/add/test_context_aware/classy',
-      ':text' => 'Test context-aware block',
     );
+    $pattern = '//tr[.//td/div[text()=:title] and .//td[text()=:category] and .//td//a[contains(@href, :href)]]';
 
     $this->drupalGet('admin/structure/block');
-    $elements = $this->xpath('//details[@id="edit-category-block-test"]//ul[contains(@class, :ul_class)]/li[contains(@class, :li_class)]/a[contains(@href, :href) and text()=:text]', $arguments);
-    $this->assertTrue(empty($elements), 'The context-aware test block does not appear.');
+    $this->clickLinkPartialName('Place block');
+    $elements = $this->xpath($pattern, $arguments);
+    $this->assertTrue(!empty($elements), 'The context-aware test block appears.');
     $definition = \Drupal::service('plugin.manager.block')->getDefinition('test_context_aware');
     $this->assertTrue(!empty($definition), 'The context-aware test block exists.');
   }
 
   /**
+   * Tests the behavior of unsatisfied context-aware blocks.
+   */
+  public function testContextAwareUnsatisfiedBlocks() {
+    $arguments = array(
+      ':title' => 'Test context-aware block',
+      ':category' => 'Block test',
+      ':href' => 'admin/structure/block/add/test_context_aware_unsatisfied/classy',
+
+    );
+    $pattern = '//tr[.//td/div[text()=:title] and .//td[text()=:category] and .//td//a[contains(@href, :href)]]';
+
+    $this->drupalGet('admin/structure/block');
+    $this->clickLinkPartialName('Place block');
+    $elements = $this->xpath($pattern, $arguments);
+    $this->assertTrue(empty($elements), 'The context-aware test block does not appear.');
+    $definition = \Drupal::service('plugin.manager.block')->getDefinition('test_context_aware_unsatisfied');
+    $this->assertTrue(!empty($definition), 'The context-aware test block exists.');
+  }
+
+  /**
    * Tests that the BlockForm populates machine name correctly.
    */
   public function testMachineNameSuggestion() {
diff --git a/core/modules/block/tests/modules/block_test/src/Plugin/Block/TestContextAwareUnsatisfiedBlock.php b/core/modules/block/tests/modules/block_test/src/Plugin/Block/TestContextAwareUnsatisfiedBlock.php
new file mode 100644
index 0000000..7232e74
--- /dev/null
+++ b/core/modules/block/tests/modules/block_test/src/Plugin/Block/TestContextAwareUnsatisfiedBlock.php
@@ -0,0 +1,34 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\block_test\Plugin\Block\TestContextAwareBlock.
+ */
+
+namespace Drupal\block_test\Plugin\Block;
+
+use Drupal\Core\Block\BlockBase;
+
+/**
+ * Provides a context-aware block.
+ *
+ * @Block(
+ *   id = "test_context_aware_unsatisfied",
+ *   admin_label = @Translation("Test context-aware unsatisfied block"),
+ *   context = {
+ *     "user" = @ContextDefinition("entity:foobar")
+ *   }
+ * )
+ */
+class TestContextAwareUnsatisfiedBlock extends BlockBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function build() {
+    return [
+      '#markup' => 'test',
+    ];
+  }
+
+}
diff --git a/core/modules/block/tests/src/Unit/BlockRepositoryTest.php b/core/modules/block/tests/src/Unit/BlockRepositoryTest.php
index d837848..5ddeab0 100644
--- a/core/modules/block/tests/src/Unit/BlockRepositoryTest.php
+++ b/core/modules/block/tests/src/Unit/BlockRepositoryTest.php
@@ -40,6 +40,11 @@ class BlockRepositoryTest extends UnitTestCase {
   protected $contextHandler;
 
   /**
+   * @var \Drupal\Core\Plugin\Context\LazyContextRepository|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $contextRepository;
+
+  /**
    * {@inheritdoc}
    */
   protected function setUp() {
@@ -65,13 +70,16 @@ protected function setUp() {
       ->will($this->returnValue($active_theme));
 
     $this->contextHandler = $this->getMock('Drupal\Core\Plugin\Context\ContextHandlerInterface');
+    $this->contextRepository = $this->getMockBuilder('Drupal\Core\Plugin\Context\LazyContextRepository')
+      ->disableOriginalConstructor()
+      ->getMock();
     $this->blockStorage = $this->getMock('Drupal\Core\Entity\EntityStorageInterface');
     $entity_manager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
     $entity_manager->expects($this->any())
       ->method('getStorage')
       ->willReturn($this->blockStorage);
 
-    $this->blockRepository = new BlockRepository($entity_manager, $theme_manager, $this->contextHandler);
+    $this->blockRepository = new BlockRepository($entity_manager, $theme_manager, $this->contextHandler, $this->contextRepository);
   }
 
   /**
diff --git a/core/modules/node/src/ContextProvider/NodeRouteContext.php b/core/modules/node/src/ContextProvider/NodeRouteContext.php
index e6f5781..6f55b08 100644
--- a/core/modules/node/src/ContextProvider/NodeRouteContext.php
+++ b/core/modules/node/src/ContextProvider/NodeRouteContext.php
@@ -13,12 +13,15 @@
 use Drupal\Core\Plugin\Context\ContextProviderInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\node\Entity\Node;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
 
 /**
  * Sets the current node as a context on node routes.
  */
 class NodeRouteContext implements ContextProviderInterface {
 
+  use StringTranslationTrait;
+
   /**
    * The route match object.
    *
@@ -63,7 +66,7 @@ public function getRuntimeContexts(array $unqualified_context_ids) {
    * {@inheritdoc}
    */
   public function getAvailableContexts() {
-    $context = new Context(new ContextDefinition('entity:node'));
+    $context = new Context(new ContextDefinition('entity:node', $this->t('Node from URL')));
     return ['node' => $context];
   }
 
diff --git a/core/tests/Drupal/Tests/Core/Annotation/ContextDefinitionTest.php b/core/tests/Drupal/Tests/Core/Annotation/ContextDefinitionTest.php
new file mode 100644
index 0000000..7f8382f
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Annotation/ContextDefinitionTest.php
@@ -0,0 +1,70 @@
+<?php
+
+/**
+ * @file Contains \Drupal\Tests\Core\Annotation\ContextDefinitionTest.
+ */
+
+namespace Drupal\Tests\Core\Annotation;
+
+use Drupal\Core\Annotation\ContextDefinition;
+use Drupal\Core\Annotation\Translation;
+use Drupal\Core\DependencyInjection\ContainerBuilder;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * @coversDefaultClass \Drupal\Core\Annotation\ContextDefinition
+ * @group Annotation
+ */
+class ContextDefinitionTest extends UnitTestCase {
+
+  /**
+   * The translation manager used for testing.
+   *
+   * @var \Drupal\Core\StringTranslation\TranslationInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $translationManager;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    $this->translationManager = $this->getStringTranslationStub();
+  }
+
+  /**
+   * Test the ContextDefinition Annotation.
+   */
+  public function testContextDefinitionAnnotation() {
+    $container = new ContainerBuilder();
+    $container->set('string_translation', $this->translationManager);
+    \Drupal::setContainer($container);
+
+    $values = [
+      'value' => 'entity:node',
+      //'label' => new Translation(['value' => 'test']),
+      'label' => 'test',
+      'description' => 'test',
+    ];
+    $context_definition = new ContextDefinition($values);
+    $definition = $context_definition->get();
+    //throw new \Exception(print_r(, TRUE));
+    // If the label or description are not a Translation annotation instance,
+    // it should be replaced by NULL.
+    $this->assertNull($definition->getLabel());
+    $this->assertNull($definition->getDescription());
+
+    $values = [
+      'value' => 'entity:node',
+      'label' => new Translation(['value' => 'test']),
+      'description' => new Translation(['value' => 'test']),
+    ];
+    $context_definition = new ContextDefinition($values);
+    $definition = $context_definition->get();
+    //throw new \Exception(print_r(, TRUE));
+    // If the label or description are a Translation annotation instance, the
+    // translated string should be returned.
+    $this->assertEquals('test', $definition->getLabel());
+    $this->assertEquals('test', $definition->getDescription());
+  }
+
+}
