diff --git a/core/modules/aggregator/aggregator.module b/core/modules/aggregator/aggregator.module
index 1a5ed475508ff062812301d43b827c9bc015ddf1..25265f430ae14c17d59b8b0ec73803f2cc7c51d0 100644
--- a/core/modules/aggregator/aggregator.module
+++ b/core/modules/aggregator/aggregator.module
@@ -547,7 +547,7 @@ function aggregator_filter_xss($value) {
  * Implements hook_preprocess_HOOK() for block.tpl.php.
  */
 function aggregator_preprocess_block(&$variables) {
-  if ($variables['block']->module == 'aggregator') {
+  if ($variables['configuration']['module'] == 'aggregator') {
     $variables['attributes']['role'] = 'complementary';
   }
 }
diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Plugin/Block/AggregatorCategoryBlock.php b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/Block/AggregatorCategoryBlock.php
index d7af2b3c754bfcc422c5e6fd9c975e2e51f369b2..b9971ce1cd102b62dcb65de2579a4ede243cbb31 100644
--- a/core/modules/aggregator/lib/Drupal/aggregator/Plugin/Block/AggregatorCategoryBlock.php
+++ b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/Block/AggregatorCategoryBlock.php
@@ -34,9 +34,9 @@ public function settings() {
   }
 
   /**
-   * Overrides \Drupal\block\BlockBase::blockAccess().
+   * Overrides \Drupal\block\BlockBase::access().
    */
-  public function blockAccess() {
+  public function access() {
     // Only grant access to users with the 'access news feeds' permission.
     return user_access('access news feeds');
   }
diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Plugin/Block/AggregatorFeedBlock.php b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/Block/AggregatorFeedBlock.php
index 4ffa57a09f5b318d37f22b18e2f99d897e0de1f1..b72936bf66d4564be09d7d16fc95bb760c3789bd 100644
--- a/core/modules/aggregator/lib/Drupal/aggregator/Plugin/Block/AggregatorFeedBlock.php
+++ b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/Block/AggregatorFeedBlock.php
@@ -34,9 +34,9 @@ public function settings() {
   }
 
   /**
-   * Overrides \Drupal\block\BlockBase::blockAccess().
+   * Overrides \Drupal\block\BlockBase::access().
    */
-  public function blockAccess() {
+  public function access() {
     // Only grant access to users with the 'access news feeds' permission.
     return user_access('access news feeds');
   }
diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Tests/AggregatorRenderingTest.php b/core/modules/aggregator/lib/Drupal/aggregator/Tests/AggregatorRenderingTest.php
index 1c6056d89e58f36574a06bd09c58c066ef3e2c63..b60dde405d709d952ccc95e7cb4d6204899ddb2a 100644
--- a/core/modules/aggregator/lib/Drupal/aggregator/Tests/AggregatorRenderingTest.php
+++ b/core/modules/aggregator/lib/Drupal/aggregator/Tests/AggregatorRenderingTest.php
@@ -50,7 +50,7 @@ public function testBlockLinks() {
     ));
     $this->drupalLogin($admin_user);
 
-    $block = $this->drupalPlaceBlock("aggregator_feed_block:{$feed->id()}", array('label' => 'feed-' . $feed->label()), array('block_count' => 2));
+    $block = $this->drupalPlaceBlock("aggregator_feed_block:{$feed->id()}", array('label' => 'feed-' . $feed->label(), 'block_count' => 2));
 
     // Confirm that the block is now being displayed on pages.
     $this->drupalGet('test-page');
diff --git a/core/modules/block/block.api.php b/core/modules/block/block.api.php
index b3c02b9a31ec09ddcf06ad4a0a41aaf4f130dda6..c2bf7ffd9e12ee362661cb60cb72df4a39f13dea 100644
--- a/core/modules/block/block.api.php
+++ b/core/modules/block/block.api.php
@@ -11,113 +11,90 @@
  */
 
 /**
- * Perform alterations to the content of a block.
+ * Alter the result of \Drupal\block\BlockBase::build().
  *
- * This hook allows you to modify any data returned by hook_block_view().
+ * This hook is called after the content has been assembled in a structured
+ * array and may be used for doing processing which requires that the complete
+ * block content structure has been built.
  *
- * Note that instead of hook_block_view_alter(), which is called for all blocks,
- * you can also use hook_block_view_ID_alter() to alter a specific block, or
- * hook_block_view_NAME_alter() to alter a specific block instance.
+ * If the module wishes to act on the rendered HTML of the block rather than
+ * the structured content array, it may use this hook to add a #post_render
+ * callback. Alternatively, it could also implement hook_preprocess_HOOK() for
+ * block.tpl.php. See drupal_render() and theme() documentation respectively
+ * for details.
+ *
+ * In addition to hook_block_view_alter(), which is called for all blocks, there
+ * is hook_block_view_BASE_BLOCK_ID_alter(), which can be used to target a
+ * specific block or set of similar blocks.
  *
  * @param array $build
  *   A renderable array of data, as returned from the build() implementation of
  *   the plugin that defined the block:
  *   - #title: The default localized title of the block.
  * @param \Drupal\block\BlockPluginInterface $block
- *   The block instance.
+ *   The block plugin instance.
  *
- * @see hook_block_view_ID_alter()
- * @see hook_block_view_NAME_alter()
+ * @see hook_block_view_BASE_BLOCK_ID_alter()
  */
-function hook_block_view_alter(array &$build, \Drupal\block\Plugin\Core\Entity\Block $block) {
+function hook_block_view_alter(array &$build, \Drupal\block\BlockPluginInterface $block) {
   // Remove the contextual links on all blocks that provide them.
-  if (is_array($build) && isset($build['#contextual_links'])) {
+  if (isset($build['#contextual_links'])) {
     unset($build['#contextual_links']);
   }
-  // Add a theme wrapper function defined by the current module to all blocks
-  // provided by the "somemodule" module.
-  if (is_array($build) && $block instanceof SomeBlockClass) {
-    $build['#theme_wrappers'][] = 'mymodule_special_block';
-  }
 }
 
 /**
- * Perform alterations to a specific block.
+ * Provide a block plugin specific block_view alteration.
  *
- * Modules can implement hook_block_view_ID_alter() to modify a specific block,
- * rather than implementing hook_block_view_alter().
+ * In this hook name, BASE_BLOCK_ID refers to the block implementation's plugin
+ * id, regardless of whether the plugin supports derivatives. For example, for
+ * the \Drupal\system\Plugin\block\block\SystemPoweredByBlock block, this would
+ * be 'system_powered_by_block' as per that class's annotation. And for the
+ * \Drupal\system\Plugin\block\block\SystemMenuBlock block, it would be
+ * 'system_menu_block' as per that class's annotation, regardless of which menu
+ * the derived block is for.
  *
  * @param array $build
  *   A renderable array of data, as returned from the build() implementation of
  *   the plugin that defined the block:
  *   - #title: The default localized title of the block.
  * @param \Drupal\block\BlockPluginInterface $block
- *   The block instance.
- *
- * @todo Add a more specific example of a block ID, and illustrate how this is
- *   different from hook_block_view_NAME_alter().
+ *   The block plugin instance.
  *
  * @see hook_block_view_alter()
- * @see hook_block_view_NAME_alter()
  */
-function hook_block_view_ID_alter(array &$build, \Drupal\block\BlockPluginInterface $block) {
-  // This code will only run for a specific block. For example, if ID
-  // in the function definition above is set to "someid", the code
-  // will only run on the "someid" block.
-
-  // Change the title of the "someid" block.
+function hook_block_view_BASE_BLOCK_ID_alter(array &$build, \Drupal\block\BlockPluginInterface $block) {
+  // Change the title of the specific block.
   $build['#title'] = t('New title of the block');
 }
 
 /**
- * Perform alterations to a specific block instance.
- *
- * Modules can implement hook_block_view_NAME_alter() to modify a specific block
- * instance, rather than implementing hook_block_view_alter().
+ * Control access to a block instance.
  *
- * @param array $build
- *   A renderable array of data, as returned from the build() implementation of
- *   the plugin that defined the block:
- *   - #title: The default localized title of the block.
- * @param \Drupal\block\BlockPluginInterface $block
- *   The block instance.
- *
- * @todo NAME is ambiguous, and so is the example here. Use a more specific
- *   example to illustrate what the block instance name will look like, and
- *   also illustrate how it is different from hook_block_view_ID().
- *
- * @see hook_block_view_alter()
- * @see hook_block_view_ID_alter()
- */
-function hook_block_view_NAME_alter(array &$build, \Drupal\block\BlockPluginInterface $block) {
-  // This code will only run for a specific block instance. For example, if NAME
-  // in the function definition above is set to "someid", the code will only run
-  // on the "someid" block.
-
-  // Change the title of the "someid" block.
-  $build['#title'] = t('New title of the block');
-}
-
-/**
- * Define access for a specific block instance.
- *
- * This hook is invoked by the access methods of the block plugin system and
- * should be used to alter the block access rules defined by a module from
- * another module.
+ * Modules may implement this hook if they want to have a say in whether or not
+ * a given user has access to perform a given operation on a block instance.
  *
  * @param \Drupal\block\Plugin\Core\Entity\Block $block
  *   The block instance.
- *
- * @return bool
- *   TRUE will allow access whereas FALSE will deny access to the block.
- *
- * @see \Drupal\block\BlockBase::access()
- * @see \Drupal\block\BlockBase::blockAccess()
+ * @param string $operation
+ *   The operation to be performed, e.g., 'view', 'create', 'delete', 'update'.
+ * @param \Drupal\user\Plugin\Core\Entity\User $account
+ *   The user object to perform the access check operation on.
+ * @param string $langcode
+ *   The language code to perform the access check operation on.
+ *
+ * @return bool|NULL
+ *   FALSE denies access. TRUE allows access unless another module returns
+ *   FALSE. If all modules return NULL, then default access rules from
+ *   \Drupal\block\BlockAccessController::checkAccess() are used.
+ *
+ * @see \Drupal\Core\Entity\EntityAccessController::access()
+ * @see \Drupal\block\BlockAccessController::checkAccess()
  */
-function hook_block_access(\Drupal\block\Plugin\Core\Entity\Block $block) {
+function hook_block_access(\Drupal\block\Plugin\Core\Entity\Block $block, $operation, \Drupal\user\Plugin\Core\Entity\User $account, $langcode) {
   // Example code that would prevent displaying the 'Powered by Drupal' block in
   // a region different than the footer.
-  if ($block->get('plugin') == 'system_powered_by_block' && $block->get('region') != 'footer') {
+  if ($operation == 'view' && $block->get('plugin') == 'system_powered_by_block' && $block->get('region') != 'footer') {
     return FALSE;
   }
 }
diff --git a/core/modules/block/block.module b/core/modules/block/block.module
index 57f15729aa113d21864e96ef4743236b3d416939..db497e32272e9ada13709b84bbda76084773a60d 100644
--- a/core/modules/block/block.module
+++ b/core/modules/block/block.module
@@ -331,10 +331,9 @@ function _block_get_renderable_region($list = array()) {
       $build[$key] = array(
         '#block' => $block,
         '#weight' => $block->get('weight'),
-        '#theme_wrappers' => array('block'),
         '#pre_render' => array('_block_get_renderable_block'),
         '#cache' => array(
-          'keys' => array($id, $block->get('module')),
+          'keys' => array($id, $settings['module']),
           'granularity' => $settings['cache'],
           'bin' => 'block',
           'tags' => array('content' => TRUE),
@@ -535,22 +534,17 @@ function block_rebuild() {
 function template_preprocess_block(&$variables) {
   $block_counter = &drupal_static(__FUNCTION__, array());
 
-  $variables['block'] = (object) $variables['elements']['#block_config'];
-  // If the block title is configured to be hidden, set it to an empty string.
-  if (empty($variables['elements']['#block']->label_display)) {
-    $variables['block']->label_hidden = $variables['block']->label;
-    $variables['block']->label = '';
-  }
-
-  // Create the $content variable that templates expect.
-  $variables['content'] = $variables['elements']['#children'];
+  $variables['configuration'] = $variables['elements']['#configuration'];
+  $variables['plugin_id'] = $variables['elements']['#plugin_id'];
+  $variables['label'] = !empty($variables['configuration']['label_display']) ? $variables['configuration']['label'] : '';
+  $variables['content'] = $variables['elements']['content'];
 
-  $variables['attributes']['class'][] = drupal_html_class('block-' . $variables['block']->module);
+  $variables['attributes']['class'][] = drupal_html_class('block-' . $variables['configuration']['module']);
 
   // Add default class for block content.
   $variables['content_attributes']['class'][] = 'content';
 
-  $variables['theme_hook_suggestions'][] = 'block__' . $variables['block']->module;
+  $variables['theme_hook_suggestions'][] = 'block__' . $variables['configuration']['module'];
   // Hyphens (-) and underscores (_) play a special role in theme suggestions.
   // Theme suggestions should only contain underscores, because within
   // drupal_find_theme_templates(), underscores are converted to hyphens to
@@ -562,7 +556,7 @@ function template_preprocess_block(&$variables) {
 
   // We can safely explode on : because we know the Block plugin type manager
   // enforces that delimiter for all derivatives.
-  $parts = explode(':', $variables['elements']['#block']->get('plugin'));
+  $parts = explode(':', $variables['plugin_id']);
   $suggestion = 'block';
   while ($part = array_shift($parts)) {
     $variables['theme_hook_suggestions'][] = $suggestion .= '__' . strtr($part, '-', '_');
diff --git a/core/modules/block/custom_block/custom_block.module b/core/modules/block/custom_block/custom_block.module
index e8ffbf09eef0b888ce4ffe3d712bb32f9c0c9063..a1fc680d1205617778bfa5e386fd5c27b23ef409 100644
--- a/core/modules/block/custom_block/custom_block.module
+++ b/core/modules/block/custom_block/custom_block.module
@@ -7,7 +7,6 @@
 
 use Drupal\custom_block\Plugin\Core\Entity\CustomBlockType;
 use Drupal\custom_block\Plugin\Core\Entity\CustomBlock;
-use Drupal\block\Plugin\Core\Entity\Block;
 
 /**
  * Implements hook_menu_local_tasks().
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Block/CustomBlockBlock.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Block/CustomBlockBlock.php
index 25c3a8675e0f4dfe219e506f360d54e3a83bbfb4..01b11ba3a789106c38fc65e8554ea9cbcb76192a 100644
--- a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Block/CustomBlockBlock.php
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Block/CustomBlockBlock.php
@@ -18,26 +18,20 @@
  *  id = "custom_block",
  *  admin_label = @Translation("Custom block"),
  *  module = "custom_block",
- *  derivative = "Drupal\custom_block\Plugin\Derivative\CustomBlock",
- *  settings = {
- *    "status" = TRUE,
- *    "info" = "",
- *    "view_mode" = "full"
- *   }
+ *  derivative = "Drupal\custom_block\Plugin\Derivative\CustomBlock"
  * )
  */
 class CustomBlockBlock extends BlockBase {
 
   /**
-   * Overrides \Drupal\block\BlockBase::getConfig().
+   * Overrides \Drupal\block\BlockBase::settings().
    */
-  public function getConfig() {
-    $definition = $this->getDefinition();
-    $this->configuration = parent::getConfig();
-    $this->configuration['status'] = $definition['settings']['status'];
-    $this->configuration['info'] = $definition['settings']['info'];
-    $this->configuration['view_mode'] = $definition['settings']['view_mode'];
-    return $this->configuration;
+  public function settings() {
+    return array(
+      'status' => TRUE,
+      'info' => '',
+      'view_mode' => 'full',
+    );
   }
 
   /**
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Derivative/CustomBlock.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Derivative/CustomBlock.php
index 592f150cfb407b5cbff7fa2467eba40cd8ba2d6c..71a50bd49b84b3855d10cd096e7f936e27a06f90 100644
--- a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Derivative/CustomBlock.php
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Derivative/CustomBlock.php
@@ -43,9 +43,6 @@ public function getDerivativeDefinitions(array $base_plugin_definition) {
     $custom_blocks = entity_load_multiple('custom_block');
     foreach ($custom_blocks as $custom_block) {
       $this->derivatives[$custom_block->uuid->value] = $base_plugin_definition;
-      $this->derivatives[$custom_block->uuid->value]['settings'] = array(
-        'info' => $custom_block->info->value,
-      ) + $base_plugin_definition['settings'];
       $this->derivatives[$custom_block->uuid->value]['admin_label'] = $custom_block->info->value;
     }
     return $this->derivatives;
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockFieldTest.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockFieldTest.php
index 8d493490c23b6339125ad1b1d89f8433f7676de4..ab9a9382383fe81c646e580a850e19016216753b 100644
--- a/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockFieldTest.php
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockFieldTest.php
@@ -101,7 +101,7 @@ public function testBlockFields() {
     // Place the block.
     $instance = array(
       'machine_name' => drupal_strtolower($edit['info']),
-      'label' => $edit['info'],
+      'settings[label]' => $edit['info'],
       'region' => 'sidebar_first',
     );
     $this->drupalPost(NULL, $instance, t('Save block'));
diff --git a/core/modules/block/lib/Drupal/block/BlockAccessController.php b/core/modules/block/lib/Drupal/block/BlockAccessController.php
index 1675cc25a411effbac3015b75b31957f058e35a0..693fb329dc2c9ee7b4a169961b8fee118330d8df 100644
--- a/core/modules/block/lib/Drupal/block/BlockAccessController.php
+++ b/core/modules/block/lib/Drupal/block/BlockAccessController.php
@@ -20,9 +20,78 @@ class BlockAccessController extends EntityAccessController {
    * {@inheritdoc}
    */
   protected function checkAccess(EntityInterface $entity, $operation, $langcode, User $account) {
-    if ($operation === 'view') {
-      return $entity->getPlugin()->access();
+    // Currently, only view access is implemented.
+    if ($operation != 'view') {
+      return FALSE;
     }
+
+    // Deny access to disabled blocks.
+    if (!$entity->status()) {
+      return FALSE;
+    }
+
+    // If the plugin denies access, then deny access.
+    if (!$entity->getPlugin()->access()) {
+      return FALSE;
+    }
+
+    // Otherwise, check for other access restrictions.
+    global $user;
+
+    // User role access handling.
+    // If a block has no roles associated, it is displayed for every role.
+    // For blocks with roles associated, if none of the user's roles matches
+    // the settings from this block, access is denied.
+    $visibility = $entity->get('visibility');
+    if (!empty($visibility['role']['roles']) && !array_intersect(array_filter($visibility['role']['roles']), array_keys($user->roles))) {
+      // No match.
+      return FALSE;
+    }
+
+    // Page path handling.
+    // Limited visibility blocks must list at least one page.
+    if (!empty($visibility['path']['visibility']) && $visibility['path']['visibility'] == BLOCK_VISIBILITY_LISTED && empty($visibility['path']['pages'])) {
+      return FALSE;
+    }
+
+    // Match path if necessary.
+    if (!empty($visibility['path']['pages'])) {
+      // Assume there are no matches until one is found.
+      $page_match = FALSE;
+
+      // Convert path to lowercase. This allows comparison of the same path
+      // with different case. Ex: /Page, /page, /PAGE.
+      $pages = drupal_strtolower($visibility['path']['pages']);
+      if ($visibility['path']['visibility'] < BLOCK_VISIBILITY_PHP) {
+        // Compare the lowercase path alias (if any) and internal path.
+        $path = current_path();
+        $path_alias = drupal_strtolower(drupal_container()->get('path.alias_manager')->getPathAlias($path));
+        $page_match = drupal_match_path($path_alias, $pages) || (($path != $path_alias) && drupal_match_path($path, $pages));
+        // When $block->visibility has a value of 0
+        // (BLOCK_VISIBILITY_NOTLISTED), the block is displayed on all pages
+        // except those listed in $block->pages. When set to 1
+        // (BLOCK_VISIBILITY_LISTED), it is displayed only on those pages
+        // listed in $block->pages.
+        $page_match = !($visibility['path']['visibility'] xor $page_match);
+      }
+      elseif (module_exists('php')) {
+        $page_match = php_eval($visibility['path']['pages']);
+      }
+
+      // If there are page visibility restrictions and this page does not
+      // match, deny access.
+      if (!$page_match) {
+        return FALSE;
+      }
+    }
+
+    // Language visibility settings.
+    if (!empty($visibility['language']['langcodes']) && array_filter($visibility['language']['langcodes'])) {
+      if (empty($visibility['language']['langcodes'][language($visibility['language']['language_type'])->langcode])) {
+        return FALSE;
+      }
+    }
+    return TRUE;
   }
 
 }
diff --git a/core/modules/block/lib/Drupal/block/BlockBase.php b/core/modules/block/lib/Drupal/block/BlockBase.php
index b1bade0c78e3b482436e4818878e18d302a3209e..57ff44db7fc86fd951f88ed7dae30e5671e36077 100644
--- a/core/modules/block/lib/Drupal/block/BlockBase.php
+++ b/core/modules/block/lib/Drupal/block/BlockBase.php
@@ -8,8 +8,6 @@
 namespace Drupal\block;
 
 use Drupal\Component\Plugin\PluginBase;
-use Drupal\block\Plugin\Core\Entity\Block;
-use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
 
 /**
  * Defines a base block implementation that most blocks plugins will extend.
@@ -21,19 +19,17 @@
 abstract class BlockBase extends PluginBase implements BlockPluginInterface {
 
   /**
-   * The entity using this plugin.
-   *
-   * @var \Drupal\block\Plugin\Core\Entity\Block
+   * {@inheritdoc}
    */
-  protected $entity;
-
-  /**
-   * Overrides \Drupal\Component\Plugin\PluginBase::__construct().
-   */
-  public function __construct(array $configuration, $plugin_id, array $plugin_definition, Block $entity) {
+  public function __construct(array $configuration, $plugin_id, array $plugin_definition) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);
 
-    $this->entity = $entity;
+    $this->configuration += $this->settings() + array(
+      'label' => '',
+      'module' => $plugin_definition['module'],
+      'label_display' => BLOCK_LABEL_VISIBLE,
+      'cache' => DRUPAL_NO_CACHE,
+    );
   }
 
   /**
@@ -65,18 +61,6 @@ public function settings() {
    * @see \Drupal\Component\Plugin\PluginBase::$configuration
    */
   public function getConfig() {
-    if (empty($this->configuration)) {
-      // If the plugin configuration is not already set, initialize it with the
-      // default settings for the block plugin.
-      $this->configuration = $this->settings();
-
-      $definition = $this->getDefinition();
-      if (isset($definition['admin_label'])) {
-        $this->configuration += array('admin_label' => $definition['admin_label']);
-      }
-    }
-    // Ensure that the default cache mode is set.
-    $this->configuration += array('cache' => DRUPAL_NO_CACHE);
     return $this->configuration;
   }
 
@@ -106,108 +90,13 @@ public function setConfig($key, $value) {
    * with that access control logic.
    *
    * @return bool
-   *   FALSE to deny access to the block, or TRUE to allow
-   *   BlockBase::access() to make the access determination.
-   *
-   * @see \Drupal\block\BlockBase::access()
-   */
-  public function blockAccess() {
-    // By default, the block is visible unless user-configured rules indicate
-    // that it should be hidden.
-    return TRUE;
-  }
-
-  /**
-   * Implements \Drupal\block\BlockPluginInterface::access().
-   *
-   * Adds the user-configured per-role, per-path, and per-language visibility
-   * settings to all blocks, and invokes hook_block_access().
-   *
-   * Most plugins should not override this method unless they need to remove
-   * the user-defined access restrictions. To add specific access
-   * restrictions for a particular block type, override
-   * BlockBase::blockAccess() instead.
+   *   FALSE to deny access to the block, or TRUE to allow access.
    *
    * @see hook_block_access()
-   * @see \Drupal\block\BlockBase::blockAccess()
    */
   public function access() {
-    // If the block-specific access restrictions indicate the block is not
-    // accessible, always deny access.
-    if (!$this->blockAccess()) {
-      return FALSE;
-    }
-
-    // Otherwise, check for other access restrictions.
-    global $user;
-
-    // Deny access to disabled blocks.
-    if (!$this->entity->get('status')) {
-      return FALSE;
-    }
-
-    // User role access handling.
-    // If a block has no roles associated, it is displayed for every role.
-    // For blocks with roles associated, if none of the user's roles matches
-    // the settings from this block, access is denied.
-    $visibility = $this->entity->get('visibility');
-    if (!empty($visibility['role']['roles']) && !array_intersect(array_filter($visibility['role']['roles']), array_keys($user->roles))) {
-      // No match.
-      return FALSE;
-    }
-
-    // Page path handling.
-    // Limited visibility blocks must list at least one page.
-    if (!empty($visibility['path']['visibility']) && $visibility['path']['visibility'] == BLOCK_VISIBILITY_LISTED && empty($visibility['path']['pages'])) {
-      return FALSE;
-    }
-
-    // Match path if necessary.
-    if (!empty($visibility['path']['pages'])) {
-      // Assume there are no matches until one is found.
-      $page_match = FALSE;
-
-      // Convert path to lowercase. This allows comparison of the same path
-      // with different case. Ex: /Page, /page, /PAGE.
-      $pages = drupal_strtolower($visibility['path']['pages']);
-      if ($visibility['path']['visibility'] < BLOCK_VISIBILITY_PHP) {
-        // Compare the lowercase path alias (if any) and internal path.
-        $path = current_path();
-        $path_alias = drupal_strtolower(drupal_container()->get('path.alias_manager')->getPathAlias($path));
-        $page_match = drupal_match_path($path_alias, $pages) || (($path != $path_alias) && drupal_match_path($path, $pages));
-        // When $block->visibility has a value of 0
-        // (BLOCK_VISIBILITY_NOTLISTED), the block is displayed on all pages
-        // except those listed in $block->pages. When set to 1
-        // (BLOCK_VISIBILITY_LISTED), it is displayed only on those pages
-        // listed in $block->pages.
-        $page_match = !($visibility['path']['visibility'] xor $page_match);
-      }
-      elseif (module_exists('php')) {
-        $page_match = php_eval($visibility['path']['pages']);
-      }
-
-      // If there are page visibility restrictions and this page does not
-      // match, deny access.
-      if (!$page_match) {
-        return FALSE;
-      }
-    }
-
-    // Language visibility settings.
-    if (!empty($visibility['language']['langcodes']) && array_filter($visibility['language']['langcodes'])) {
-      if (empty($visibility['language']['langcodes'][language($visibility['language']['language_type'])->langcode])) {
-        return FALSE;
-      }
-    }
-
-    // Check other modules for block access rules.
-    foreach (module_implements('block_access') as $module) {
-      if (module_invoke($module, 'block_access', $this->entity) === FALSE) {
-        return FALSE;
-      }
-    }
-
-    // If nothing denied access to the block, it is accessible.
+    // By default, the block is visible unless user-configured rules indicate
+    // that it should be hidden.
     return TRUE;
   }
 
@@ -222,12 +111,7 @@ public function access() {
    * @see \Drupal\block\BlockBase::blockForm()
    */
   public function form($form, &$form_state) {
-    $entity = $form_state['controller']->getEntity();
     $definition = $this->getDefinition();
-    $form['id'] = array(
-      '#type' => 'value',
-      '#value' => $entity->id(),
-    );
     $form['module'] = array(
       '#type' => 'value',
       '#value' => $definition['module'],
@@ -237,164 +121,18 @@ public function form($form, &$form_state) {
       '#type' => 'textfield',
       '#title' => t('Title'),
       '#maxlength' => 255,
-      '#default_value' => !$entity->isNew() ? $entity->label() : $definition['admin_label'],
+      '#default_value' => !empty($this->configuration['label']) ? $this->configuration['label'] : $definition['admin_label'],
       '#required' => TRUE,
     );
     $form['label_display'] = array(
       '#type' => 'checkbox',
       '#title' => t('Display title'),
-      '#default_value' => $entity->label_display == BLOCK_LABEL_VISIBLE ? TRUE : FALSE,
+      '#default_value' => $this->configuration['label_display'] == BLOCK_LABEL_VISIBLE,
       '#return_value' => BLOCK_LABEL_VISIBLE,
     );
-    $form['machine_name'] = array(
-      '#type' => 'machine_name',
-      '#title' => t('Machine name'),
-      '#maxlength' => 64,
-      '#description' => t('A unique name to save this block configuration. Must be alpha-numeric and be underscore separated.'),
-      '#default_value' => $entity->id(),
-      '#machine_name' => array(
-        'exists' => 'block_load',
-        'replace_pattern' => '[^a-z0-9_.]+',
-      ),
-      '#required' => TRUE,
-      '#disabled' => !$entity->isNew(),
-    );
-
-    // Region settings.
-    $form['region'] = array(
-      '#type' => 'select',
-      '#title' => t('Region'),
-      '#description' => t('Select the region where this block should be displayed.'),
-      '#default_value' => $entity->get('region'),
-      '#empty_value' => BLOCK_REGION_NONE,
-      '#options' => system_region_list($entity->get('theme'), REGIONS_VISIBLE),
-    );
-
-    // Visibility settings.
-    $form['visibility'] = array(
-      '#type' => 'vertical_tabs',
-      '#title' => t('Visibility settings'),
-      '#attached' => array(
-        'js' => array(drupal_get_path('module', 'block') . '/block.js'),
-      ),
-      '#tree' => TRUE,
-      '#weight' => 10,
-    );
-
-    // Per-path visibility.
-    $form['visibility']['path'] = array(
-      '#type' => 'details',
-      '#title' => t('Pages'),
-      '#collapsed' => TRUE,
-      '#group' => 'visibility',
-      '#weight' => 0,
-    );
-
-    // @todo remove this access check and inject it in some other way. In fact
-    //   this entire visibility settings section probably needs a separate user
-    //   interface in the near future.
-    $visibility = $entity->get('visibility');
-    $access = user_access('use PHP for settings');
-    if (!empty($visibility['path']['visibility']) && $visibility['path']['visibility'] == BLOCK_VISIBILITY_PHP && !$access) {
-      $form['visibility']['path']['visibility'] = array(
-        '#type' => 'value',
-        '#value' => BLOCK_VISIBILITY_PHP,
-      );
-      $form['visibility']['path']['pages'] = array(
-        '#type' => 'value',
-        '#value' => !empty($visibility['path']['pages']) ? $visibility['path']['pages'] : '',
-      );
-    }
-    else {
-      $options = array(
-        BLOCK_VISIBILITY_NOTLISTED => t('All pages except those listed'),
-        BLOCK_VISIBILITY_LISTED => t('Only the listed pages'),
-      );
-      $description = t("Specify pages by using their paths. Enter one path per line. The '*' character is a wildcard. Example paths are %user for the current user's page and %user-wildcard for every user page. %front is the front page.", array('%user' => 'user', '%user-wildcard' => 'user/*', '%front' => '<front>'));
-
-      if (module_exists('php') && $access) {
-        $options += array(BLOCK_VISIBILITY_PHP => t('Pages on which this PHP code returns <code>TRUE</code> (experts only)'));
-        $title = t('Pages or PHP code');
-        $description .= ' ' . t('If the PHP option is chosen, enter PHP code between %php. Note that executing incorrect PHP code can break your Drupal site.', array('%php' => '<?php ?>'));
-      }
-      else {
-        $title = t('Pages');
-      }
-      $form['visibility']['path']['visibility'] = array(
-        '#type' => 'radios',
-        '#title' => t('Show block on specific pages'),
-        '#options' => $options,
-        '#default_value' => !empty($visibility['path']['visibility']) ? $visibility['path']['visibility'] : BLOCK_VISIBILITY_NOTLISTED,
-      );
-      $form['visibility']['path']['pages'] = array(
-        '#type' => 'textarea',
-        '#title' => '<span class="element-invisible">' . $title . '</span>',
-        '#default_value' => !empty($visibility['path']['pages']) ? $visibility['path']['pages'] : '',
-        '#description' => $description,
-      );
-    }
-
-    // Configure the block visibility per language.
-    if (module_exists('language') && language_multilingual()) {
-      $configurable_language_types = language_types_get_configurable();
-
-      // Fetch languages.
-      $languages = language_list(LANGUAGE_ALL);
-      foreach ($languages as $language) {
-        // @todo $language->name is not wrapped with t(), it should be replaced
-        //   by CMI translation implementation.
-        $langcodes_options[$language->langcode] = $language->name;
-      }
-      $form['visibility']['language'] = array(
-        '#type' => 'details',
-        '#title' => t('Languages'),
-        '#collapsed' => TRUE,
-        '#group' => 'visibility',
-        '#weight' => 5,
-      );
-      // If there are multiple configurable language types, let the user pick
-      // which one should be applied to this visibility setting. This way users
-      // can limit blocks by interface language or content language for exmaple.
-      $language_types = language_types_info();
-      $language_type_options = array();
-      foreach ($configurable_language_types as $type_key) {
-        $language_type_options[$type_key] = $language_types[$type_key]['name'];
-      }
-      $form['visibility']['language']['language_type'] = array(
-        '#type' => 'radios',
-        '#title' => t('Language type'),
-        '#options' => $language_type_options,
-        '#default_value' => !empty($visibility['language']['language_type']) ? $visibility['language']['language_type'] : $configurable_language_types[0],
-        '#access' => count($language_type_options) > 1,
-      );
-      $form['visibility']['language']['langcodes'] = array(
-        '#type' => 'checkboxes',
-        '#title' => t('Show this block only for specific languages'),
-        '#default_value' => !empty($visibility['language']['langcodes']) ? $visibility['language']['langcodes'] : array(),
-        '#options' => $langcodes_options,
-        '#description' => t('Show this block only for the selected language(s). If you select no languages, the block will be visibile in all languages.'),
-      );
-    }
-
-    // Per-role visibility.
-    $role_options = array_map('check_plain', user_role_names());
-    $form['visibility']['role'] = array(
-      '#type' => 'details',
-      '#title' => t('Roles'),
-      '#collapsed' => TRUE,
-      '#group' => 'visibility',
-      '#weight' => 10,
-    );
-    $form['visibility']['role']['roles'] = array(
-      '#type' => 'checkboxes',
-      '#title' => t('Show block for specific roles'),
-      '#default_value' => !empty($visibility['role']['roles']) ? $visibility['role']['roles'] : array(),
-      '#options' => $role_options,
-      '#description' => t('Show this block only for the selected role(s). If you select no roles, the block will be visible to all users.'),
-    );
 
     // Add plugin-specific settings for this block type.
-    $form['settings'] = $this->blockForm(array(), $form_state);
+    $form += $this->blockForm($form, $form_state);
     return $form;
   }
 
@@ -429,15 +167,6 @@ public function blockForm($form, &$form_state) {
    * @see \Drupal\block\BlockBase::blockValidate()
    */
   public function validate($form, &$form_state) {
-    $entity = $form_state['controller']->getEntity();
-    if (!empty($form['machine_name']['#disabled'])) {
-      $config_id = explode('.', $form_state['values']['machine_name']);
-      $form_state['values']['machine_name'] = array_pop($config_id);
-    }
-    $form_state['values']['visibility']['role']['roles'] = array_filter($form_state['values']['visibility']['role']['roles']);
-    if ($entity->isNew()) {
-      form_set_value($form['id'], $entity->get('theme') . '.' . $form_state['values']['machine_name'], $form_state);
-    }
     $this->blockValidate($form, $form_state);
   }
 
@@ -471,12 +200,10 @@ public function blockValidate($form, &$form_state) {}
    */
   public function submit($form, &$form_state) {
     if (!form_get_errors()) {
+      $this->configuration['label'] = $form_state['values']['label'];
+      $this->configuration['label_display'] = $form_state['values']['label_display'];
+      $this->configuration['module'] = $form_state['values']['module'];
       $this->blockSubmit($form, $form_state);
-      $entity = $form_state['controller']->getEntity();
-
-      drupal_set_message(t('The block configuration has been saved.'));
-      cache_invalidate_tags(array('content' => TRUE));
-      $form_state['redirect'] = 'admin/structure/block/list/block_plugin_ui:' . $entity->get('theme');
     }
   }
 
@@ -502,9 +229,20 @@ public function blockSubmit($form, &$form_state) {}
    * Implements \Drupal\block\BlockInterface::build().
    */
   public function build() {
-    // @todo Move block rendering code common to all blocks from
-    //   BlockRenderController to here: http://drupal.org/node/1927608.
-    return $this->blockBuild();
+    $build = array();
+    $plugin_id = $this->getPluginId();
+    if ($content = $this->blockBuild()) {
+      $build = array(
+        '#theme' => 'block',
+        'content' => $content,
+        '#configuration' => $this->configuration,
+        '#plugin_id' => $plugin_id,
+      );
+      $build['#configuration']['label'] = check_plain($this->configuration['label']);
+    }
+    list($base_id) = explode(':', $plugin_id);
+    drupal_alter(array('block_view', "block_view_$base_id"), $build, $this);
+    return $build;
   }
 
   /**
diff --git a/core/modules/block/lib/Drupal/block/BlockFormController.php b/core/modules/block/lib/Drupal/block/BlockFormController.php
index 175d6b09fa78b137bd794a32c45020b2c6e0b013..ef499c043f7439b36cabc1b2dab02e4660bbb805 100644
--- a/core/modules/block/lib/Drupal/block/BlockFormController.php
+++ b/core/modules/block/lib/Drupal/block/BlockFormController.php
@@ -18,7 +18,163 @@ class BlockFormController extends EntityFormController {
    * Overrides \Drupal\Core\Entity\EntityFormController::form().
    */
   public function form(array $form, array &$form_state) {
-    return $this->entity->getPlugin()->form($form, $form_state);
+    $entity = $this->entity;
+    $form['#tree'] = TRUE;
+    $form['id'] = array(
+      '#type' => 'value',
+      '#value' => $entity->id(),
+    );
+    $form['settings'] = $entity->getPlugin()->form(array(), $form_state);
+
+    $form['machine_name'] = array(
+      '#type' => 'machine_name',
+      '#title' => t('Machine name'),
+      '#maxlength' => 64,
+      '#description' => t('A unique name to save this block configuration. Must be alpha-numeric and be underscore separated.'),
+      '#default_value' => $entity->id(),
+      '#machine_name' => array(
+        'exists' => 'block_load',
+        'replace_pattern' => '[^a-z0-9_.]+',
+        'source' => array('settings', 'label'),
+      ),
+      '#required' => TRUE,
+      '#disabled' => !$entity->isNew(),
+    );
+
+    // Visibility settings.
+    $form['visibility'] = array(
+      '#type' => 'vertical_tabs',
+      '#title' => t('Visibility settings'),
+      '#attached' => array(
+        'js' => array(drupal_get_path('module', 'block') . '/block.js'),
+      ),
+      '#tree' => TRUE,
+      '#weight' => 10,
+      '#parents' => array('visibility'),
+    );
+
+    // Per-path visibility.
+    $form['visibility']['path'] = array(
+      '#type' => 'details',
+      '#title' => t('Pages'),
+      '#collapsed' => TRUE,
+      '#group' => 'visibility',
+      '#weight' => 0,
+    );
+
+    // @todo remove this access check and inject it in some other way. In fact
+    //   this entire visibility settings section probably needs a separate user
+    //   interface in the near future.
+    $visibility = $entity->get('visibility');
+    $access = user_access('use PHP for settings');
+    if (!empty($visibility['path']['visibility']) && $visibility['path']['visibility'] == BLOCK_VISIBILITY_PHP && !$access) {
+      $form['visibility']['path']['visibility'] = array(
+        '#type' => 'value',
+        '#value' => BLOCK_VISIBILITY_PHP,
+      );
+      $form['visibility']['path']['pages'] = array(
+        '#type' => 'value',
+        '#value' => !empty($visibility['path']['pages']) ? $visibility['path']['pages'] : '',
+      );
+    }
+    else {
+      $options = array(
+        BLOCK_VISIBILITY_NOTLISTED => t('All pages except those listed'),
+        BLOCK_VISIBILITY_LISTED => t('Only the listed pages'),
+      );
+      $description = t("Specify pages by using their paths. Enter one path per line. The '*' character is a wildcard. Example paths are %user for the current user's page and %user-wildcard for every user page. %front is the front page.", array('%user' => 'user', '%user-wildcard' => 'user/*', '%front' => '<front>'));
+
+      if (module_exists('php') && $access) {
+        $options += array(BLOCK_VISIBILITY_PHP => t('Pages on which this PHP code returns <code>TRUE</code> (experts only)'));
+        $title = t('Pages or PHP code');
+        $description .= ' ' . t('If the PHP option is chosen, enter PHP code between %php. Note that executing incorrect PHP code can break your Drupal site.', array('%php' => '<?php ?>'));
+      }
+      else {
+        $title = t('Pages');
+      }
+      $form['visibility']['path']['visibility'] = array(
+        '#type' => 'radios',
+        '#title' => t('Show block on specific pages'),
+        '#options' => $options,
+        '#default_value' => !empty($visibility['path']['visibility']) ? $visibility['path']['visibility'] : BLOCK_VISIBILITY_NOTLISTED,
+      );
+      $form['visibility']['path']['pages'] = array(
+        '#type' => 'textarea',
+        '#title' => '<span class="element-invisible">' . $title . '</span>',
+        '#default_value' => !empty($visibility['path']['pages']) ? $visibility['path']['pages'] : '',
+        '#description' => $description,
+      );
+    }
+
+    // Configure the block visibility per language.
+    if (module_exists('language') && language_multilingual()) {
+      $configurable_language_types = language_types_get_configurable();
+
+      // Fetch languages.
+      $languages = language_list(LANGUAGE_ALL);
+      foreach ($languages as $language) {
+        // @todo $language->name is not wrapped with t(), it should be replaced
+        //   by CMI translation implementation.
+        $langcodes_options[$language->langcode] = $language->name;
+      }
+      $form['visibility']['language'] = array(
+        '#type' => 'details',
+        '#title' => t('Languages'),
+        '#collapsed' => TRUE,
+        '#group' => 'visibility',
+        '#weight' => 5,
+      );
+      // If there are multiple configurable language types, let the user pick
+      // which one should be applied to this visibility setting. This way users
+      // can limit blocks by interface language or content language for exmaple.
+      $language_types = language_types_info();
+      $language_type_options = array();
+      foreach ($configurable_language_types as $type_key) {
+        $language_type_options[$type_key] = $language_types[$type_key]['name'];
+      }
+      $form['visibility']['language']['language_type'] = array(
+        '#type' => 'radios',
+        '#title' => t('Language type'),
+        '#options' => $language_type_options,
+        '#default_value' => !empty($visibility['language']['language_type']) ? $visibility['language']['language_type'] : $configurable_language_types[0],
+        '#access' => count($language_type_options) > 1,
+      );
+      $form['visibility']['language']['langcodes'] = array(
+        '#type' => 'checkboxes',
+        '#title' => t('Show this block only for specific languages'),
+        '#default_value' => !empty($visibility['language']['langcodes']) ? $visibility['language']['langcodes'] : array(),
+        '#options' => $langcodes_options,
+        '#description' => t('Show this block only for the selected language(s). If you select no languages, the block will be visibile in all languages.'),
+      );
+    }
+
+    // Per-role visibility.
+    $role_options = array_map('check_plain', user_role_names());
+    $form['visibility']['role'] = array(
+      '#type' => 'details',
+      '#title' => t('Roles'),
+      '#collapsed' => TRUE,
+      '#group' => 'visibility',
+      '#weight' => 10,
+    );
+    $form['visibility']['role']['roles'] = array(
+      '#type' => 'checkboxes',
+      '#title' => t('Show block for specific roles'),
+      '#default_value' => !empty($visibility['role']['roles']) ? $visibility['role']['roles'] : array(),
+      '#options' => $role_options,
+      '#description' => t('Show this block only for the selected role(s). If you select no roles, the block will be visible to all users.'),
+    );
+
+    // Region settings.
+    $form['region'] = array(
+      '#type' => 'select',
+      '#title' => t('Region'),
+      '#description' => t('Select the region where this block should be displayed.'),
+      '#default_value' => $entity->get('region'),
+      '#empty_value' => BLOCK_REGION_NONE,
+      '#options' => system_region_list($entity->get('theme'), REGIONS_VISIBLE),
+    );
+    return $form;
   }
 
   /**
@@ -37,7 +193,21 @@ public function validate(array $form, array &$form_state) {
     parent::validate($form, $form_state);
 
     $entity = $this->entity;
-    $entity->getPlugin()->validate($form, $form_state);
+    if ($entity->isNew()) {
+      form_set_value($form['id'], $entity->get('theme') . '.' . $form_state['values']['machine_name'], $form_state);
+    }
+    if (!empty($form['machine_name']['#disabled'])) {
+      $config_id = explode('.', $form_state['values']['machine_name']);
+      $form_state['values']['machine_name'] = array_pop($config_id);
+    }
+    $form_state['values']['visibility']['role']['roles'] = array_filter($form_state['values']['visibility']['role']['roles']);
+    // The Block Entity form puts all block plugin form elements in the
+    // settings form element, so just pass that to the block for validation.
+    $settings = array(
+      'values' => &$form_state['values']['settings']
+    );
+    // Call the plugin validate handler.
+    $entity->getPlugin()->validate($form, $settings);
   }
 
   /**
@@ -47,12 +217,20 @@ public function submit(array $form, array &$form_state) {
     parent::submit($form, $form_state);
 
     $entity = $this->entity;
+    // The Block Entity form puts all block plugin form elements in the
+    // settings form element, so just pass that to the block for submission.
+    $settings = array(
+      'values' => &$form_state['values']['settings']
+    );
     // Call the plugin submit handler.
-    $entity->getPlugin()->submit($form, $form_state);
+    $entity->getPlugin()->submit($form, $settings);
 
     // Save the settings of the plugin.
-    $entity->set('settings', $entity->getPlugin()->getConfig());
     $entity->save();
+
+    drupal_set_message(t('The block configuration has been saved.'));
+    cache_invalidate_tags(array('content' => TRUE));
+    $form_state['redirect'] = 'admin/structure/block/list/block_plugin_ui:' . $entity->get('theme');
   }
 
 }
diff --git a/core/modules/block/lib/Drupal/block/BlockListController.php b/core/modules/block/lib/Drupal/block/BlockListController.php
index 5dd981fbdb3b55e7e7fb98101235c53fbade5ff4..5b18b3c69a0fa23beb4ac51ea03c723560101c7f 100644
--- a/core/modules/block/lib/Drupal/block/BlockListController.php
+++ b/core/modules/block/lib/Drupal/block/BlockListController.php
@@ -206,6 +206,12 @@ public function submitForm(array &$form, array &$form_state) {
     foreach ($entities as $entity_id => $entity) {
       $entity->set('weight', $form_state['values']['blocks'][$entity_id]['weight']);
       $entity->set('region', $form_state['values']['blocks'][$entity_id]['region']);
+      if ($entity->get('region') == BLOCK_REGION_NONE) {
+        $entity->disable();
+      }
+      else {
+        $entity->enable();
+      }
       $entity->save();
     }
     drupal_set_message(t('The block settings have been updated.'));
diff --git a/core/modules/block/lib/Drupal/block/BlockPluginBag.php b/core/modules/block/lib/Drupal/block/BlockPluginBag.php
new file mode 100644
index 0000000000000000000000000000000000000000..5a68beb4bafbaeef5ddb44a89b06a0a05dce6e57
--- /dev/null
+++ b/core/modules/block/lib/Drupal/block/BlockPluginBag.php
@@ -0,0 +1,69 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\block\BlockPluginBag.
+ */
+
+namespace Drupal\block;
+
+use Drupal\block\Plugin\Core\Entity\Block;
+use Drupal\Component\Plugin\PluginBag;
+use Drupal\Component\Plugin\PluginManagerInterface;
+use Drupal\Component\Plugin\Exception\PluginException;
+
+/**
+ * Provides a collection of block plugins.
+ */
+class BlockPluginBag extends PluginBag {
+
+  /**
+   * The manager used to instantiate the plugins.
+   *
+   * @var \Drupal\Component\Plugin\PluginManagerInterface
+   */
+  protected $manager;
+
+  /**
+   * Constructs a BlockPluginBag object.
+   *
+   * @param \Drupal\Component\Plugin\PluginManagerInterface $manager
+   *   The manager to be used for instantiating plugins.
+   * @param array $instance_ids
+   *   The ids of the plugin instances with which we are dealing.
+   * @param \Drupal\block\Plugin\Core\Entity\Block $entity
+   *   The Block entity that holds our configuration.
+   */
+  public function __construct(PluginManagerInterface $manager, array $instance_ids, Block $entity) {
+    $this->manager = $manager;
+    $this->entity = $entity;
+
+    $this->instanceIDs = drupal_map_assoc($instance_ids);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function initializePlugin($instance_id) {
+    if (!$instance_id) {
+      throw new PluginException(format_string("The block '@block' did not specify a plugin.", array('@block' => $this->entity->id())));
+    }
+    if (isset($this->pluginInstances[$instance_id])) {
+      return;
+    }
+
+    $settings = $this->entity->get('settings');
+    try {
+      $this->pluginInstances[$instance_id] = $this->manager->createInstance($instance_id, $settings);
+    }
+    catch (PluginException $e) {
+      $module = $settings['module'];
+      // Ignore blocks belonging to disabled modules, but re-throw valid
+      // exceptions when the module is enabled and the plugin is misconfigured.
+      if (!$module || \Drupal::moduleHandler()->moduleExists($module)) {
+        throw $e;
+      }
+    }
+  }
+
+}
diff --git a/core/modules/block/lib/Drupal/block/BlockRenderController.php b/core/modules/block/lib/Drupal/block/BlockRenderController.php
index e1c560e37558184147ee4cbfc39ad384721692f3..12fff822840b259fb6c7ea13035abf69382f7935 100644
--- a/core/modules/block/lib/Drupal/block/BlockRenderController.php
+++ b/core/modules/block/lib/Drupal/block/BlockRenderController.php
@@ -22,42 +22,6 @@ public function buildContent(array $entities, array $displays, $view_mode, $lang
     return array();
   }
 
-  /**
-   * Provides entity-specific defaults to the build process.
-   *
-   * @param Drupal\Core\Entity\EntityInterface $entity
-   *   The entity for which the defaults should be provided.
-   * @param string $view_mode
-   *   The view mode that should be used.
-   * @param string $langcode
-   *   (optional) For which language the entity should be prepared, defaults to
-   *   the current content language.
-   *
-   * @return array
-   *   An array of defaults to add into the entity render array.
-   */
-  protected function getBuildDefaults(EntityInterface $entity, $view_mode, $langcode) {
-    // @todo \Drupal\block\Tests\BlockTest::testCustomBlock() assuemes that a
-    //   block can be rendered without any of its wrappers. To do so, it uses a
-    //   custom view mode, and we choose to only add the wrappers on the default
-    //   view mode, 'block'.
-    if ($view_mode != 'block') {
-      return array();
-    }
-
-    return array(
-      '#block' => $entity,
-      '#weight' => $entity->get('weight'),
-      '#theme_wrappers' => array('block'),
-      '#block_config' => array(
-        'id' => $entity->get('plugin'),
-        'region' => $entity->get('region'),
-        'module' => $entity->get('module'),
-        'label' => check_plain($entity->label()),
-      ),
-    );
-  }
-
   /**
    * Implements Drupal\Core\Entity\EntityRenderControllerInterface::view().
    */
@@ -72,17 +36,10 @@ public function view(EntityInterface $entity, $view_mode = 'full', $langcode = N
   public function viewMultiple(array $entities = array(), $view_mode = 'full', $langcode = NULL) {
     $build = array();
     foreach ($entities as $entity_id => $entity) {
-      // Allow blocks to be empty, do not add in the defaults.
-      if ($content = $entity->getPlugin()->build()) {
-        $build[$entity_id] = $this->getBuildDefaults($entity, $view_mode, $langcode);
-      }
-      $build[$entity_id]['content'] = $content;
-
-      // All blocks, even when empty, should be available for altering.
-      $id = str_replace(':', '__', $entity->get('plugin'));
-      list(, $name) = $entity->id();
-      drupal_alter(array('block_view', "block_view_$id", "block_view_$name"), $build[$entity_id], $entity);
+      $build[$entity_id] = $entity->getPlugin()->build();
 
+      // @todo Remove after fixing http://drupal.org/node/1989568.
+      $build[$entity_id]['#block'] = $entity;
     }
     return $build;
   }
diff --git a/core/modules/block/lib/Drupal/block/BlockStorageController.php b/core/modules/block/lib/Drupal/block/BlockStorageController.php
index a873c5dcfe91c4017128b60f4027a776b753bf8a..80ce276128dbbacb389c5ae511c47470269173d3 100644
--- a/core/modules/block/lib/Drupal/block/BlockStorageController.php
+++ b/core/modules/block/lib/Drupal/block/BlockStorageController.php
@@ -16,21 +16,7 @@
 class BlockStorageController extends ConfigStorageController {
 
   /**
-   * Overrides \Drupal\Core\Config\Entity\ConfigStorageController::create().
-   */
-  public function create(array $values) {
-    $entity = parent::create($values);
-
-    if (!$entity->get('module')) {
-      $definition = $entity->getPlugin()->getDefinition();
-      $entity->set('module', $definition['module']);
-    }
-
-    return $entity;
-  }
-
-  /**
-   * Overrides \Drupal\Core\Config\Entity\ConfigStorageController::load().
+   * {@inheritdoc}
    */
   public function load(array $ids = NULL) {
     $entities = parent::load($ids);
@@ -41,7 +27,7 @@ public function load(array $ids = NULL) {
   }
 
   /**
-   * Overrides \Drupal\Core\Config\Entity\ConfigStorageController::loadByProperties().
+   * {@inheritdoc}
    */
   public function loadByProperties(array $values = array()) {
     $blocks = $this->load();
@@ -53,4 +39,13 @@ public function loadByProperties(array $values = array()) {
     return $blocks;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function preSave(EntityInterface $entity) {
+    parent::preSave($entity);
+
+    $entity->set('settings', $entity->getPlugin()->getConfig());
+  }
+
 }
diff --git a/core/modules/block/lib/Drupal/block/Form/AdminBlockDeleteForm.php b/core/modules/block/lib/Drupal/block/Form/AdminBlockDeleteForm.php
index 8db943b1a966abd4f022e6214164af62c5969f21..ba6206a302347eafc7fcff3f77c8e1f5702c541c 100644
--- a/core/modules/block/lib/Drupal/block/Form/AdminBlockDeleteForm.php
+++ b/core/modules/block/lib/Drupal/block/Form/AdminBlockDeleteForm.php
@@ -33,7 +33,7 @@ public function getFormID() {
    * {@inheritdoc}
    */
   protected function getQuestion() {
-    return t('Are you sure you want to delete the block %name?', array('%name' => $this->block->label));
+    return t('Are you sure you want to delete the block %name?', array('%name' => $this->block->label()));
   }
 
   /**
diff --git a/core/modules/block/lib/Drupal/block/Plugin/Core/Entity/Block.php b/core/modules/block/lib/Drupal/block/Plugin/Core/Entity/Block.php
index fd0498fffccfc9e74119bbe0e02ab0c011bca9a0..3c8b14c171e289f92cbe1942f9dad0ad2b2bedf1 100644
--- a/core/modules/block/lib/Drupal/block/Plugin/Core/Entity/Block.php
+++ b/core/modules/block/lib/Drupal/block/Plugin/Core/Entity/Block.php
@@ -10,7 +10,7 @@
 use Drupal\Core\Config\Entity\ConfigEntityBase;
 use Drupal\Core\Entity\Annotation\EntityType;
 use Drupal\Core\Annotation\Translation;
-use Drupal\Component\Plugin\Exception\PluginException;
+use Drupal\block\BlockPluginBag;
 use Drupal\block\BlockInterface;
 
 /**
@@ -48,24 +48,6 @@ class Block extends ConfigEntityBase implements BlockInterface {
    */
   public $id;
 
-  /**
-   * The block label.
-   *
-   * @var string
-   */
-  public $label;
-
-  /**
-   * Whether the block label is displayed to end users.
-   *
-   * When this is set to BLOCK_LABEL_VISIBLE (the default value), the label is
-   * rendered as header in the block markup. Otherwise, the label is passed
-   * to the block template as a separate $label_hidden variable.
-   *
-   * @var string
-   */
-  public $label_display = BLOCK_LABEL_VISIBLE;
-
   /**
    * The block UUID.
    *
@@ -80,13 +62,6 @@ class Block extends ConfigEntityBase implements BlockInterface {
    */
   protected $settings = array();
 
-  /**
-   * The plugin instance.
-   *
-   * @var \Drupal\block\BlockPluginInterface
-   */
-  protected $instance;
-
   /**
    * The region this block is placed in.
    *
@@ -95,57 +70,47 @@ class Block extends ConfigEntityBase implements BlockInterface {
   protected $region = BLOCK_REGION_NONE;
 
   /**
-   * Settings to control the block visibility.
+   * The block weight.
    *
-   * @var array
+   * @var int
    */
-  protected $visibility = array();
+  public $weight;
 
   /**
-   * The weight of the block.
+   * The plugin instance ID.
    *
-   * @var int
+   * @var string
    */
-  protected $weight;
+  protected $plugin;
 
   /**
-   * The module owning this plugin.
+   * The plugin bag that holds the block plugin for this entity.
    *
-   * @var string
+   * @var \Drupal\block\BlockPluginBag
    */
-  protected $module;
+  protected $pluginBag;
 
   /**
-   * The plugin instance ID.
+   * The visibility settings.
    *
-   * @var string
+   * @var array
    */
-  protected $plugin;
+  protected $visibility;
+
+  /**
+   * Overrides \Drupal\Core\Config\Entity\ConfigEntityBase::__construct();
+   */
+  public function __construct(array $values, $entity_type) {
+    parent::__construct($values, $entity_type);
+
+    $this->pluginBag = new BlockPluginBag(\Drupal::service('plugin.manager.block'), array($this->plugin), $this);
+  }
 
   /**
    * {@inheritdoc}
    */
   public function getPlugin() {
-    if (!$this->instance) {
-      // Throw an exception if no plugin string was provided.
-      if (!$this->plugin) {
-        throw new PluginException(format_string("The block '@block' did not specify a plugin.", array('@block' => $this->id())));
-      }
-
-      // Create a plugin instance and store its configuration as settings.
-      try {
-        $this->instance = drupal_container()->get('plugin.manager.block')->createInstance($this->plugin, $this->settings, $this);
-        $this->settings += $this->instance->getConfig();
-      }
-      catch (PluginException $e) {
-        // Ignore blocks belonging to disabled modules, but re-throw valid
-        // exceptions when the module is enabled and the plugin is misconfigured.
-        if (empty($this->module) || module_exists($this->module)) {
-          throw $e;
-        }
-      }
-    }
-    return $this->instance;
+    return $this->pluginBag->get($this->plugin);
   }
 
   /**
@@ -160,6 +125,13 @@ public function uri() {
       ),
     );
   }
+  /**
+   * Overrides \Drupal\Core\Entity\Entity::label();
+   */
+  public function label($langcode = NULL) {
+    $settings = $this->get('settings');
+    return $settings['label'];
+  }
 
   /**
    * Overrides \Drupal\Core\Config\Entity\ConfigEntityBase::get();
@@ -177,21 +149,14 @@ public function get($property_name, $langcode = NULL) {
    * Overrides \Drupal\Core\Config\Entity\ConfigEntityBase::getExportProperties();
    */
   public function getExportProperties() {
+    $properties = parent::getExportProperties();
     $names = array(
-      'id',
-      'label',
-      'label_display',
-      'uuid',
       'region',
       'weight',
-      'module',
-      'status',
-      'visibility',
       'plugin',
       'settings',
-      'langcode',
+      'visibility',
     );
-    $properties = array();
     foreach ($names as $name) {
       $properties[$name] = $this->get($name);
     }
diff --git a/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php b/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php
index 488722cea9c16803ce7faf47e63455ee74f3a9c4..19cdf60c3f450966cbecf79e11b3da8dc8df3223 100644
--- a/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php
+++ b/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php
@@ -13,7 +13,6 @@
 use Drupal\Core\Plugin\Discovery\AlterDecorator;
 use Drupal\Core\Plugin\Discovery\CacheDecorator;
 use Drupal\Component\Plugin\Factory\DefaultFactory;
-use Drupal\block\Plugin\Core\Entity\Block;
 
 /**
  * Manages discovery and instantiation of block plugins.
@@ -36,15 +35,8 @@ public function __construct(\Traversable $namespaces) {
     $this->discovery = new DerivativeDiscoveryDecorator($this->discovery);
     $this->discovery = new AlterDecorator($this->discovery, 'block');
     $this->discovery = new CacheDecorator($this->discovery, 'block_plugins:' . language(LANGUAGE_TYPE_INTERFACE)->langcode, 'block', CacheBackendInterface::CACHE_PERMANENT, array('block'));
-  }
 
-  /**
-   * Overrides \Drupal\Component\Plugin\PluginManagerBase::createInstance().
-   */
-  public function createInstance($plugin_id, array $configuration = array(), Block $entity = NULL) {
-    $plugin_definition = $this->discovery->getDefinition($plugin_id);
-    $plugin_class = DefaultFactory::getPluginClass($plugin_id, $plugin_definition);
-    return new $plugin_class($configuration, $plugin_id, $plugin_definition, $entity);
+    $this->factory = new DefaultFactory($this->discovery);
   }
 
 }
diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockCacheTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockCacheTest.php
index 96f9343d188077b0712063201ad914665993e865..46454a6c6dccb1482a503be37c3415a265753ba6 100644
--- a/core/modules/block/lib/Drupal/block/Tests/BlockCacheTest.php
+++ b/core/modules/block/lib/Drupal/block/Tests/BlockCacheTest.php
@@ -192,9 +192,7 @@ function testCachePerPage() {
    * Private helper method to set the test block's cache mode.
    */
   private function setCacheMode($cache_mode) {
-    $settings = $this->block->get('settings');
-    $settings['cache'] = $cache_mode;
-    $this->block->set('settings', $settings);
+    $this->block->getPlugin()->setConfig('cache', $cache_mode);
     $this->block->save();
   }
 
diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockInterfaceTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockInterfaceTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..58ff0c2d4fe8472592213a76011871459ccfbcb0
--- /dev/null
+++ b/core/modules/block/lib/Drupal/block/Tests/BlockInterfaceTest.php
@@ -0,0 +1,111 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\block\Tests\BlockInterfaceTest.
+ */
+
+namespace Drupal\block\Tests;
+
+use Drupal\simpletest\DrupalUnitTestBase;
+
+/**
+ * Test BlockInterface methods to ensure no external dependencies exist.
+ */
+class BlockInterfaceTest extends DrupalUnitTestBase {
+  public static $modules = array('system', 'block', 'block_test', 'user');
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Block Plugins Tests',
+      'description' => 'Tests that the block plugin can work properly without a supporting entity.',
+      'group' => 'Block',
+    );
+  }
+
+  protected function setUp() {
+    parent::setUp();
+    $this->installSchema('user', 'role_permission');
+  }
+
+  /**
+   * Test configuration and subsequent form() and build() method calls.
+   *
+   * This test is attempting to test the existing block plugin api and all
+   * functionality that is expected to remain consistent. The arrays that are
+   * used for comparison can change, but only to include elements that are
+   * contained within BlockBase or the plugin being tested. Likely these
+   * comparison arrays should get smaller, not larger, as more form/build
+   * elements are moved into a more suitably responsible class.
+   *
+   * Instantiation of the plugin is the primary element being tested here. The
+   * subsequent method calls are just attempting to cause a failure if a
+   * dependency outside of the plugin configuration is required.
+   */
+  public function testBlockInterface() {
+    $manager = $this->container->get('plugin.manager.block');
+    $configuration = array(
+      'label' => 'Custom Display Message',
+    );
+    $expected_configuration = array(
+      'label' => 'Custom Display Message',
+      'display_message' => 'no message set',
+      'module' => 'block_test',
+      'label_display' => BLOCK_LABEL_VISIBLE,
+      'cache' => DRUPAL_NO_CACHE,
+    );
+    // Initial configuration of the block at construction time.
+    $display_block = $manager->createInstance('test_block_instantiation', $configuration);
+    $this->assertIdentical($display_block->getConfig(), $expected_configuration, 'The block was configured correctly.');
+
+    // Updating an element of the configuration.
+    $display_block->setConfig('display_message', 'My custom display message.');
+    $expected_configuration['display_message'] = 'My custom display message.';
+    $this->assertIdentical($display_block->getConfig(), $expected_configuration, 'The block configuration was updated correctly.');
+
+    $expected_form = array(
+      'module' => array(
+        '#type' => 'value',
+        '#value' => 'block_test',
+      ),
+      'label' => array(
+        '#type' => 'textfield',
+        '#title' => 'Title',
+        '#maxlength' => 255,
+        '#default_value' => 'Custom Display Message',
+        '#required' => TRUE,
+      ),
+      'label_display' => array(
+        '#type' => 'checkbox',
+        '#title' => 'Display title',
+        '#default_value' => TRUE,
+        '#return_value' => 'visible',
+      ),
+      'display_message' => array(
+        '#type' => 'textfield',
+        '#title' => t('Display message'),
+        '#default_value' => 'My custom display message.',
+      ),
+    );
+    $form_state = array();
+    // Ensure there are no form elements that do not belong to the plugin.
+    $this->assertIdentical($display_block->form(array(), $form_state), $expected_form, 'Only the expected form elements were present.');
+
+    $expected_build = array(
+      '#theme' => 'block',
+      'content' => array(
+        '#children' => 'My custom display message.',
+      ),
+      '#configuration' => array(
+        'label' => 'Custom Display Message',
+        'display_message' => 'My custom display message.',
+        'module' => 'block_test',
+        'label_display' => BLOCK_LABEL_VISIBLE,
+        'cache' => DRUPAL_NO_CACHE,
+      ),
+      '#plugin_id' => 'test_block_instantiation',
+    );
+    // Ensure the build array is proper.
+    $this->assertIdentical($display_block->build(), $expected_build, 'The plugin returned the appropriate build array.');
+  }
+}
diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockLanguageTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockLanguageTest.php
index f24764825a4f05d18d77c4c631a9748e31535007..69d5ccd545f9c62e72dd4c33ed3803ae3ce6a9a2 100644
--- a/core/modules/block/lib/Drupal/block/Tests/BlockLanguageTest.php
+++ b/core/modules/block/lib/Drupal/block/Tests/BlockLanguageTest.php
@@ -105,8 +105,8 @@ public function testLanguageBlockVisibilityLanguageDelete() {
 
     // Check that we have the language in config after saving the setting.
     $visibility = $block->get('visibility');
-    $setting = $visibility['language']['langcodes']['fr'];
-    $this->assertTrue('fr' === $setting, 'Language is set in the block configuration.');
+    $language = $visibility['language']['langcodes']['fr'];
+    $this->assertTrue('fr' === $language, 'Language is set in the block configuration.');
 
     // Delete the language.
     $this->drupalPost('admin/config/regional/language/delete/fr', array(), t('Delete'));
diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockStorageUnitTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockStorageUnitTest.php
index af060dbae8394c8ba219ac7d51875c2176f7c063..dfc3b61bd21a20c616c8b06b78b6355f4d6da202 100644
--- a/core/modules/block/lib/Drupal/block/Tests/BlockStorageUnitTest.php
+++ b/core/modules/block/lib/Drupal/block/Tests/BlockStorageUnitTest.php
@@ -69,6 +69,7 @@ protected function createTests() {
     // Attempt to create a block without a plugin.
     try {
       $entity = $this->controller->create(array());
+      $entity->getPlugin();
       $this->fail('A block without a plugin was created with no exception thrown.');
     }
     catch (PluginException $e) {
@@ -92,19 +93,18 @@ protected function createTests() {
     // Ensure that default values are filled in.
     $expected_properties = array(
       'id' => 'stark.test_block',
-      'label' => '',
-      'label_display' => BLOCK_LABEL_VISIBLE,
-      'region' => '-1',
       'weight' => '',
-      'module' => 'block_test',
       'status' => '1',
-      'visibility' => array(),
+      'langcode' => language_default()->langcode,
+      'region' => '-1',
       'plugin' => 'test_html_id',
       'settings' => array(
         'cache' => '1',
-        'admin_label' => t('Test block html id'),
+        'label' => '',
+        'module' => 'block_test',
+        'label_display' => BLOCK_LABEL_VISIBLE,
       ),
-      'langcode' => language_default()->langcode,
+      'visibility' => '',
     );
     $this->assertIdentical($actual_properties, $expected_properties, 'The block properties are exported correctly.');
 
@@ -124,7 +124,6 @@ protected function loadTests() {
     $this->assertEqual($entity->get('region'), '-1');
     $this->assertTrue($entity->get('status'));
     $this->assertEqual($entity->get('theme'), 'stark');
-    $this->assertEqual($entity->get('module'), 'block_test');
     $this->assertTrue($entity->uuid());
   }
 
@@ -132,12 +131,8 @@ protected function loadTests() {
    * Tests the rendering of blocks.
    */
   protected function renderTests() {
-    $entity = $this->controller->create(array(
-      'id' => 'stark.test_block',
-      'plugin' => 'test_html_id',
-    ));
-
     // Test the rendering of a block.
+    $entity = entity_load('block', 'stark.test_block');
     $output = entity_view($entity, 'block');
     $expected = array();
     $expected[] = '  <div id="block-test-block"  class="block block-block-test">';
@@ -154,10 +149,17 @@ protected function renderTests() {
     drupal_static_reset('drupal_html_id');
 
     // Test the rendering of a block with a given title.
-    $entity->set('label', 'Powered by Bananas');
+    $entity = $this->controller->create(array(
+      'id' => 'stark.test_block2',
+      'plugin' => 'test_html_id',
+      'settings' => array(
+        'label' => 'Powered by Bananas',
+      ),
+    ));
+    $entity->save();
     $output = entity_view($entity, 'block');
     $expected = array();
-    $expected[] = '  <div id="block-test-block"  class="block block-block-test">';
+    $expected[] = '  <div id="block-test-block2"  class="block block-block-test">';
     $expected[] = '';
     $expected[] = '    <h2>Powered by Bananas</h2>';
     $expected[] = '  ';
@@ -167,6 +169,8 @@ protected function renderTests() {
     $expected[] = '';
     $expected_output = implode("\n", $expected);
     $this->assertEqual(drupal_render($output), $expected_output, 'The block rendered correctly.');
+    // Clean up this entity.
+    $entity->delete();
   }
 
   /**
diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockTemplateSuggestionsUnitTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockTemplateSuggestionsUnitTest.php
index 95f2cf1be62745effdec3a6df0f890c4a489f438..9f3ffe12d853b865c940032455f6931892336a80 100644
--- a/core/modules/block/lib/Drupal/block/Tests/BlockTemplateSuggestionsUnitTest.php
+++ b/core/modules/block/lib/Drupal/block/Tests/BlockTemplateSuggestionsUnitTest.php
@@ -45,12 +45,9 @@ function testBlockThemeHookSuggestions() {
 
     $variables = array();
     $variables['elements']['#block'] = $block;
-    $variables['elements']['#block_config'] = $block->getPlugin()->getConfig() + array(
-      'id' => $block->get('plugin'),
-      'region' => $block->get('region'),
-      'module' => $block->get('module'),
-    );
-    $variables['elements']['#children'] = '';
+    $variables['elements']['#configuration'] = $block->getPlugin()->getConfig();
+    $variables['elements']['#plugin_id'] = $block->get('plugin');
+    $variables['elements']['content'] = array();
     // Test adding a class to the block content.
     $variables['content_attributes']['class'][] = 'test-class';
     template_preprocess_block($variables);
diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockTest.php
index 902008773f79afa05baa7d2f80d72e576e634c07..75bcb39a43aa6a5a19e6527c5c97d61f39b2784f 100644
--- a/core/modules/block/lib/Drupal/block/Tests/BlockTest.php
+++ b/core/modules/block/lib/Drupal/block/Tests/BlockTest.php
@@ -34,7 +34,7 @@ function testBlockVisibility() {
     $edit = array(
       'machine_name' => strtolower($this->randomName(8)),
       'region' => 'sidebar_first',
-      'label' => $title,
+      'settings[label]' => $title,
     );
     // Set the block to be hidden on any user path, and to be shown only to
     // authenticated users.
@@ -75,7 +75,7 @@ function testBlockVisibilityListedEmpty() {
     $edit = array(
       'machine_name' => strtolower($this->randomName(8)),
       'region' => 'sidebar_first',
-      'label' => $title,
+      'settings[label]' => $title,
       'visibility[path][visibility]' => BLOCK_VISIBILITY_LISTED,
     );
     // Set the block to be hidden on any user path, and to be shown only to
@@ -102,18 +102,18 @@ function testBlock() {
     // Select the 'Powered by Drupal' block to be configured and moved.
     $block = array();
     $block['id'] = 'system_powered_by_block';
-    $block['label'] = $this->randomName(8);
+    $block['settings[label]'] = $this->randomName(8);
     $block['machine_name'] = strtolower($this->randomName(8));
     $block['theme'] = config('system.theme')->get('default');
     $block['region'] = 'header';
 
     // Set block title to confirm that interface works and override any custom titles.
-    $this->drupalPost('admin/structure/block/add/' . $block['id'] . '/' . $block['theme'], array('label' => $block['label'], 'machine_name' => $block['machine_name'], 'region' => $block['region']), t('Save block'));
+    $this->drupalPost('admin/structure/block/add/' . $block['id'] . '/' . $block['theme'], array('settings[label]' => $block['settings[label]'], 'machine_name' => $block['machine_name'], 'region' => $block['region']), t('Save block'));
     $this->assertText(t('The block configuration has been saved.'), 'Block title set.');
     // Check to see if the block was created by checking its configuration.
     $instance = entity_load('block', $block['theme'] . '.' . $block['machine_name']);
 
-    $this->assertEqual($instance->label(), $block['label'], 'Stored block title found.');
+    $this->assertEqual($instance->label(), $block['settings[label]'], 'Stored block title found.');
 
     // Check whether the block can be moved to all available regions.
     foreach ($this->regions as $region) {
@@ -130,7 +130,7 @@ function testBlock() {
 
     // Confirm that the block instance title and markup are not displayed.
     $this->drupalGet('node');
-    $this->assertNoText(t($block['label']));
+    $this->assertNoText(t($block['settings[label]']));
     // Check for <div id="block-my-block-instance-name"> if the machine name
     // is my_block_instance_name.
     $xpath = $this->buildXPathQuery('//div[@id=:id]/*', array(':id' => 'block-' . strtr(strtolower($block['machine_name']), '-', '_')));
@@ -150,7 +150,7 @@ function testHideBlockTitle() {
     $edit = array(
       'machine_name' => $machine_name,
       'region' => 'sidebar_first',
-      'label' => $title,
+      'settings[label]' => $title,
     );
     $this->drupalPost('admin/structure/block/add/' . $block_name . '/' . $default_theme, $edit, t('Save block'));
     $this->assertText('The block configuration has been saved.', 'Block was saved');
@@ -159,7 +159,7 @@ function testHideBlockTitle() {
     $this->assertText($title, 'Block title was displayed by default.');
 
     $edit = array(
-      'label_display' => FALSE,
+      'settings[label_display]' => FALSE,
     );
     $this->drupalPost('admin/structure/block/manage/' . $default_theme . '.' . $machine_name . '/configure', $edit, t('Save block'));
     $this->assertText('The block configuration has been saved.', 'Block was saved');
@@ -192,7 +192,7 @@ function moveBlockToRegion(array $block, $region) {
 
     // Confirm that the block is being displayed.
     $this->drupalGet('');
-    $this->assertText(t($block['label']), 'Block successfully being displayed on the page.');
+    $this->assertText(t($block['settings[label]']), 'Block successfully being displayed on the page.');
 
     // Confirm that the custom block was found at the proper region.
     $xpath = $this->buildXPathQuery('//div[@class=:region-class]//div[@id=:block-id]/*', array(
@@ -225,8 +225,7 @@ function testBlockRehash() {
     $this->assertEqual($settings['cache'], DRUPAL_CACHE_PER_ROLE, 'Test block cache mode defaults to DRUPAL_CACHE_PER_ROLE.');
 
     // Disable caching for this block.
-    $settings['cache'] = DRUPAL_NO_CACHE;
-    $block->set('settings', $settings);
+    $block->getPlugin()->setConfig('cache', DRUPAL_NO_CACHE);
     $block->save();
     // Flushing all caches should call _block_rehash().
     $this->resetAll();
@@ -290,13 +289,13 @@ function testBlockModuleDisable() {
     // Emulate a POST submission rather than using drupalPlaceBlock() to ensure
     // that the form still functions as expected.
     $edit = array(
-      'label' => $this->randomName(8),
+      'settings[label]' => $this->randomName(8),
       'machine_name' => strtolower($this->randomName(8)),
       'region' => 'sidebar_first',
     );
     $this->drupalPost('admin/structure/block/add/system_powered_by_block/stark', $edit, t('Save block'));
     $this->assertText(t('The block configuration has been saved.'));
-    $this->assertText($edit['label']);
+    $this->assertText($edit['settings[label]']);
 
     // Update the weight of a block.
     $edit = array('blocks[stark.' . $edit['machine_name'] . '][weight]' => -1);
diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockTitleXSSTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockTitleXSSTest.php
index b04f9fccf52e18f74a78183d01298453d79a7dc5..7ac364873fab4827ef767612dc0eb8c3feb17cf7 100644
--- a/core/modules/block/lib/Drupal/block/Tests/BlockTitleXSSTest.php
+++ b/core/modules/block/lib/Drupal/block/Tests/BlockTitleXSSTest.php
@@ -32,10 +32,7 @@ public static function getInfo() {
   protected function setUp() {
     parent::setUp();
 
-    $this->drupalPlaceBlock('test_xss_title', array(
-      'label' => '<script>alert("XSS label");</script>',
-      'machine_name' => 'test_xss_block',
-    ));
+    $this->drupalPlaceBlock('test_xss_title', array('label' => '<script>alert("XSS label");</script>'));
   }
 
   /**
diff --git a/core/modules/block/lib/Drupal/block/Tests/Views/DisplayBlockTest.php b/core/modules/block/lib/Drupal/block/Tests/Views/DisplayBlockTest.php
index 617f33d8ac7e7db804b08a6ec698fb98a5f73f05..7178e6c78d9bcdc8cc432e7aa4f594613bd2669f 100644
--- a/core/modules/block/lib/Drupal/block/Tests/Views/DisplayBlockTest.php
+++ b/core/modules/block/lib/Drupal/block/Tests/Views/DisplayBlockTest.php
@@ -90,13 +90,13 @@ protected function findBlockInstance(Block $block) {
   protected function testDeleteBlockDisplay() {
     // To test all combinations possible we first place create two instances
     // of the block display of the first view.
-    $block_1 = $this->drupalPlaceBlock('views_block:test_view_block-block_1', array(), array('title' => 'test_view_block-block_1:1'));
-    $block_2 = $this->drupalPlaceBlock('views_block:test_view_block-block_1', array(), array('title' => 'test_view_block-block_1:2'));
+    $block_1 = $this->drupalPlaceBlock('views_block:test_view_block-block_1', array('title' => 'test_view_block-block_1:1'));
+    $block_2 = $this->drupalPlaceBlock('views_block:test_view_block-block_1', array('title' => 'test_view_block-block_1:2'));
 
     // Then we add one instance of blocks for each of the two displays of the
     // second view.
-    $block_3 = $this->drupalPlaceBlock('views_block:test_view_block2-block_1', array(), array('title' => 'test_view_block2-block_1'));
-    $block_4 = $this->drupalPlaceBlock('views_block:test_view_block2-block_2', array(), array('title' => 'test_view_block2-block_2'));
+    $block_3 = $this->drupalPlaceBlock('views_block:test_view_block2-block_1', array('title' => 'test_view_block2-block_1'));
+    $block_4 = $this->drupalPlaceBlock('views_block:test_view_block2-block_2', array('title' => 'test_view_block2-block_2'));
 
     $this->drupalGet('test-page');
     $this->assertBlockAppears($block_1);
diff --git a/core/modules/block/templates/block.tpl.php b/core/modules/block/templates/block.tpl.php
index 4b301fab2b374d6d87fe5ca14716c325d7576668..106dd6b3566becebddbe85a1aaacb259824e1c20 100644
--- a/core/modules/block/templates/block.tpl.php
+++ b/core/modules/block/templates/block.tpl.php
@@ -5,13 +5,15 @@
  * Default theme implementation to display a block.
  *
  * Available variables:
- * - $block->label: Block title.
- * - $block->label_hidden: The hidden block title value if the block was
- *    configured to hide the title ($block->label is empty in this case).
+ * - $plugin_id: The ID of the block implementation.
+ * - $label: The configured label of the block if visible.
+ * - $configuration: An array of the block's configuration values.
+ *   - label: The configured label for the block.
+ *   - label_display: The display settings for the label.
+ *   - module: The module that provided this block plugin.
+ *   - cache: The cache settings.
+ *   - Block plugin specific settings will also be stored here.
  * - $content: Block content.
- * - $block->module: Module that generated the block.
- * - $block->delta: An ID for the block, unique within each module.
- * - $block->region: The block region embedding the current block.
  * - $attributes: An instance of Attributes class that can be manipulated as an
  *    array and printed as a string.
  *    It includes the 'class' information, which includes:
@@ -46,12 +48,12 @@
 <?php endif; ?>
 
   <?php print render($title_prefix); ?>
-<?php if ($block->label): ?>
-  <h2<?php print $title_attributes; ?>><?php print $block->label; ?></h2>
+<?php if ($label): ?>
+  <h2<?php print $title_attributes; ?>><?php print $label; ?></h2>
 <?php endif;?>
   <?php print render($title_suffix); ?>
 
   <div<?php print $content_attributes; ?>>
-    <?php print $content ?>
+    <?php print render($content) ?>
   </div>
 </div>
diff --git a/core/modules/block/tests/config/block.block.stark.test_block.yml b/core/modules/block/tests/config/block.block.stark.test_block.yml
index 59ba7b4c0eab7440a6eb2ecfca4a247208cfbf4a..e8b5ade35db39104f1345c20f31eee9454725cd7 100644
--- a/core/modules/block/tests/config/block.block.stark.test_block.yml
+++ b/core/modules/block/tests/config/block.block.stark.test_block.yml
@@ -1,11 +1,20 @@
 id: stark.test_block
-label: ''
-region: '-1'
 weight: ''
-module: block_test
 status: '1'
-visibility: {  }
+langcode: en
+region: '-1'
 plugin: test_html_id
 settings:
+  label: 'Test block html id"'
+  module: block_test
+  label_display: '0'
   cache: '1'
-  admin_label: 'Test block html id'
+visibility:
+  path:
+    visibility: '0'
+    pages: ''
+  role:
+    roles: {  }
+  node_type:
+    types: {  }
+  visibility__active_tab: edit-visibility-path
diff --git a/core/modules/block/tests/lib/Drupal/block_test/Plugin/Block/TestBlockInstantiation.php b/core/modules/block/tests/lib/Drupal/block_test/Plugin/Block/TestBlockInstantiation.php
new file mode 100644
index 0000000000000000000000000000000000000000..ba45a4e3dbd7905228358d1bedf5b93a4bbb878a
--- /dev/null
+++ b/core/modules/block/tests/lib/Drupal/block_test/Plugin/Block/TestBlockInstantiation.php
@@ -0,0 +1,69 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\block_test\Plugin\Block\TestBlockInstantiation.
+ */
+
+namespace Drupal\block_test\Plugin\Block;
+
+use Drupal\block\BlockBase;
+use Drupal\Component\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
+
+/**
+ * Provides a basic block for testing block instantiation and configuration.
+ *
+ * @Plugin(
+ *   id = "test_block_instantiation",
+ *   admin_label = @Translation("Display message"),
+ *   module = "block_test"
+ * )
+ */
+class TestBlockInstantiation extends BlockBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function settings() {
+    return array(
+      'display_message' => 'no message set',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function access() {
+    return user_access('access content');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function blockForm($form, &$form_state) {
+    $form['display_message'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Display message'),
+      '#default_value' => $this->configuration['display_message'],
+    );
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function blockSubmit($form, &$form_state) {
+    $this->configuration['display_message'] = $form_state['values']['display_message'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function blockBuild() {
+    return array(
+      '#children' => $this->configuration['display_message'],
+    );
+  }
+
+}
diff --git a/core/modules/book/book.module b/core/modules/book/book.module
index a94b8f260427287fd206455750e1fbf507ecd535..887f95f19b81810c67a4b80c2d10d94aa2ebea15 100644
--- a/core/modules/book/book.module
+++ b/core/modules/book/book.module
@@ -962,7 +962,7 @@ function _book_link_defaults($nid) {
  * Implements hook_preprocess_HOOK() for block.tpl.php.
  */
 function book_preprocess_block(&$variables) {
-  if ($variables['block']-> module == 'book') {
+  if ($variables['configuration']['module'] == 'book') {
     $variables['attributes']['role'] = 'navigation';
   }
 }
diff --git a/core/modules/book/lib/Drupal/book/Tests/BookTest.php b/core/modules/book/lib/Drupal/book/Tests/BookTest.php
index fd5d4c04c6522fed3386471346200dce305f1614..eba9ff9857edb15226018a059feb0e8b73f19808 100644
--- a/core/modules/book/lib/Drupal/book/Tests/BookTest.php
+++ b/core/modules/book/lib/Drupal/book/Tests/BookTest.php
@@ -338,7 +338,7 @@ function testBookNavigationBlock() {
    */
   function testNavigationBlockOnAccessModuleEnabled() {
     $this->drupalLogin($this->admin_user);
-    $block = $this->drupalPlaceBlock('book_navigation', array(), array('block_mode' => 'book pages'));
+    $block = $this->drupalPlaceBlock('book_navigation', array('block_mode' => 'book pages'));
 
     // Give anonymous users the permission 'node test view'.
     $edit = array();
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index 6d0d003fd550d431a0eab3659aa825edfa2bdfb4..7d848d6188c82452e71152b248e1a1e19ead07fe 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -1530,7 +1530,7 @@ function comment_preview(Comment $comment) {
  * Implements hook_preprocess_HOOK() for block.tpl.php.
  */
 function comment_preprocess_block(&$variables) {
-  if ($variables['block']->module == 'comment') {
+  if ($variables['configuration']['module'] == 'comment') {
     $variables['attributes']['role'] = 'navigation';
   }
 }
diff --git a/core/modules/comment/lib/Drupal/comment/Plugin/Block/RecentCommentsBlock.php b/core/modules/comment/lib/Drupal/comment/Plugin/Block/RecentCommentsBlock.php
index 14601c0d290428da7afecec333b640084e62863a..387f7ceaed3683052408bca7b3e70aac61a3bfee 100644
--- a/core/modules/comment/lib/Drupal/comment/Plugin/Block/RecentCommentsBlock.php
+++ b/core/modules/comment/lib/Drupal/comment/Plugin/Block/RecentCommentsBlock.php
@@ -34,7 +34,7 @@ public function settings() {
   /**
    * Overrides \Drupal\block\BlockBase::access().
    */
-  public function blockAccess() {
+  public function access() {
     return user_access('access comments');
   }
 
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentBlockTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentBlockTest.php
index 901d325ab154f64cfb0233f106d4032dfb9e5093..89f81b15354ae120c2bd6ac90cabe9de81794d13 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentBlockTest.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentBlockTest.php
@@ -46,7 +46,7 @@ public static function getInfo() {
    */
   function testRecentCommentBlock() {
     $this->drupalLogin($this->admin_user);
-    $block = $this->drupalPlaceBlock('recent_comments', array(), array('block_count' => 2));
+    $block = $this->drupalPlaceBlock('recent_comments', array('block_count' => 2));
 
     // Add some test comments, one without a subject.
     $comment1 = $this->postComment($this->node, $this->randomName(), $this->randomName());
@@ -78,7 +78,7 @@ function testRecentCommentBlock() {
     $this->assertTrue(strpos($this->drupalGetContent(), $comment3->comment_body->value) < strpos($this->drupalGetContent(), $comment2->subject->value), 'Comments were ordered correctly in block.');
 
     // Set the number of recent comments to show to 10.
-    $block->set('settings', array('block_count' => 10));
+    $block->getPlugin()->setConfig('block_count', 10);
     $block->save();
 
     // Post an additional comment.
diff --git a/core/modules/forum/forum.module b/core/modules/forum/forum.module
index af1330e0c8961fdcf8df1a1a618b1609ab2dff85..20e8631dfc1f3ac880fa440f35602cc2dff6971b 100644
--- a/core/modules/forum/forum.module
+++ b/core/modules/forum/forum.module
@@ -649,7 +649,8 @@ function forum_form_node_form_alter(&$form, &$form_state, $form_id) {
  *
  * This function can be used as a #pre_render callback.
  *
- * @see forum_block_view()
+ * @see \Drupal\forum\Plugin\block\block\NewTopicsBlock::blockBuild()
+ * @see \Drupal\forum\Plugin\block\block\ActiveTopicsBlock::blockBuild()
  */
 function forum_block_view_pre_render($elements) {
   $result = $elements['#query']->execute();
@@ -972,7 +973,7 @@ function forum_get_topics($tid, $sortby, $forum_per_page) {
  * Implements hook_preprocess_HOOK() for block.tpl.php.
  */
 function forum_preprocess_block(&$variables) {
-  if ($variables['block']->module == 'forum') {
+  if ($variables['configuration']['module'] == 'forum') {
     $variables['attributes']['role'] = 'navigation';
   }
 }
diff --git a/core/modules/forum/lib/Drupal/forum/Plugin/Block/ForumBlockBase.php b/core/modules/forum/lib/Drupal/forum/Plugin/Block/ForumBlockBase.php
index 4d9d64c4d331d9440eaebdc0f7e67e94a54763a9..cbdfc795089447bb5d342b095cfe0c9ebd3e6cc8 100644
--- a/core/modules/forum/lib/Drupal/forum/Plugin/Block/ForumBlockBase.php
+++ b/core/modules/forum/lib/Drupal/forum/Plugin/Block/ForumBlockBase.php
@@ -28,9 +28,9 @@ public function settings() {
   }
 
   /**
-   * Overrides \Drupal\block\BlockBase::blockAccess().
+   * Overrides \Drupal\block\BlockBase::access().
    */
-  public function blockAccess() {
+  public function access() {
     return user_access('access content');
   }
 
diff --git a/core/modules/forum/lib/Drupal/forum/Tests/ForumBlockTest.php b/core/modules/forum/lib/Drupal/forum/Tests/ForumBlockTest.php
index 02314e88e869401bd4e295a0b0ad888bb074a804..65dd7c2ecf7e581fe7da7005ccae3186125ad56a 100644
--- a/core/modules/forum/lib/Drupal/forum/Tests/ForumBlockTest.php
+++ b/core/modules/forum/lib/Drupal/forum/Tests/ForumBlockTest.php
@@ -71,7 +71,7 @@ public function testNewForumTopicsBlock() {
     }
 
     // Configure the new forum topics block to only show 2 topics.
-    $block->set('settings', array('block_count' => 2));
+    $block->getPlugin()->setConfig('block_count', 2);
     $block->save();
 
     $this->drupalGet('');
@@ -132,7 +132,7 @@ public function testActiveForumTopicsBlock() {
     }
 
     // Configure the active forum block to only show 2 topics.
-    $block->set('settings', array('block_count' => 2));
+    $block->getPlugin()->setConfig('block_count', 2);
     $block->save();
 
     $this->drupalGet('');
diff --git a/core/modules/help/help.module b/core/modules/help/help.module
index be57134e55004c9c64d22b8aab5845cd596f954e..d7042d320075f62f1142f9f89a8b8a6461c78daa 100644
--- a/core/modules/help/help.module
+++ b/core/modules/help/help.module
@@ -69,7 +69,7 @@ function help_help($path, $arg) {
  * Implements hook_preprocess_HOOK() for block.tpl.php.
  */
 function help_preprocess_block(&$variables) {
-  if ($variables['block']->id == 'system_help_block') {
+  if ($variables['plugin_id'] == 'system_help_block') {
     $variables['attributes']['role'] = 'complementary';
   }
 }
diff --git a/core/modules/language/language.module b/core/modules/language/language.module
index 2f2966c9622650d084911eb31bef755a6df9ef23..6294f3143fcbf748f6df38812fa63421c4082105 100644
--- a/core/modules/language/language.module
+++ b/core/modules/language/language.module
@@ -763,7 +763,7 @@ function language_language_delete($language) {
  * Implements hook_preprocess_HOOK() for block.tpl.php.
  */
 function language_preprocess_block(&$variables) {
-  if ($variables['block']->module == 'language') {
+  if ($variables['configuration']['module'] == 'language') {
     $variables['attributes']['role'] = 'navigation';
   }
 }
diff --git a/core/modules/language/lib/Drupal/language/Plugin/Block/LanguageBlock.php b/core/modules/language/lib/Drupal/language/Plugin/Block/LanguageBlock.php
index 3c64703dc5553f287233d065b959836df64a5cd4..4ab3bfd444c775348a3cd397c287510fcbebdf57 100644
--- a/core/modules/language/lib/Drupal/language/Plugin/Block/LanguageBlock.php
+++ b/core/modules/language/lib/Drupal/language/Plugin/Block/LanguageBlock.php
@@ -24,9 +24,9 @@
 class LanguageBlock extends BlockBase {
 
   /**
-   * Overrides \Drupal\block\BlockBase::blockAccess().
+   * Overrides \Drupal\block\BlockBase::access().
    */
-  function blockAccess() {
+  function access() {
     return language_multilingual();
   }
 
diff --git a/core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php b/core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php
index 89287f5564204ed5f6142ff7aa31be86a8ea95d1..f3a4391c211dce3c417c648a8be2f00a838e0ee2 100644
--- a/core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php
+++ b/core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php
@@ -16,7 +16,7 @@ class MenuTest extends WebTestBase {
    *
    * @var array
    */
-  public static $modules = array('menu', 'block', 'test_page_test');
+  public static $modules = array('menu', 'block', 'test_page_test', 'contextual');
 
   protected $big_user;
   protected $std_user;
@@ -302,6 +302,17 @@ function testSystemMenuRename() {
     $this->assertText($edit['label']);
   }
 
+  /**
+   * Tests the contextual links on a menu block.
+   */
+  public function testBlockContextualLinks() {
+    $this->drupalLogin($this->drupalCreateUser(array('administer menu', 'access contextual links')));
+    $this->addMenuLink();
+    $this->drupalPlaceBlock('system_menu_block:menu-tools', array('label' => 'Tools', 'module' => 'system'));
+    $this->drupalGet('test-page');
+    $this->assertLinkByHref("admin/structure/menu/manage/tools/edit");
+  }
+
   /**
    * Add a menu link using the menu module UI.
    *
diff --git a/core/modules/menu/menu.module b/core/modules/menu/menu.module
index b63891781c205756ded0e6e4df2d6f9e9e239976..93c2ed815203f758097997b23850e5d9b6960e88 100644
--- a/core/modules/menu/menu.module
+++ b/core/modules/menu/menu.module
@@ -12,9 +12,8 @@
  */
 
 use Drupal\Core\Entity\EntityInterface;
-use Drupal\block\Plugin\Core\Entity\Block;
+use Drupal\block\BlockPluginInterface;
 use Drupal\system\Plugin\Core\Entity\Menu;
-use Drupal\system\Plugin\Block\SystemMenuBlock;
 use Symfony\Component\HttpFoundation\JsonResponse;
 use Drupal\menu_link\Plugin\Core\Entity\MenuLink;
 use Drupal\menu_link\MenuLinkStorageController;
@@ -399,13 +398,13 @@ function _menu_parents_recurse($tree, $menu_name, $indent, &$options, $exclude,
 }
 
 /**
- * Implements hook_block_view_alter().
+ * Implements hook_block_view_BASE_BLOCK_ID_alter() for 'system_menu_block'.
  */
-function menu_block_view_alter(array &$build, Block $block) {
+function menu_block_view_system_menu_block_alter(array &$build, BlockPluginInterface $block) {
   // Add contextual links for system menu blocks.
-  if ($block->getPlugin() instanceof SystemMenuBlock) {
+  if (isset($build['content'])) {
     foreach (element_children($build['content']) as $key) {
-      $build['#contextual_links']['menu'] = array('admin/structure/menu/manage', array($build['content'][$key]['#original_link']['menu_name']));
+      $build['content']['#contextual_links']['menu'] = array('admin/structure/menu/manage', array($build['content'][$key]['#original_link']['menu_name']));
     }
   }
 }
@@ -717,7 +716,7 @@ function menu_get_menus($all = TRUE) {
  * Implements hook_preprocess_HOOK() for block.tpl.php.
  */
 function menu_preprocess_block(&$variables) {
-  if ($variables['block']->module == 'menu') {
+  if ($variables['configuration']['module'] == 'menu') {
     $variables['attributes']['role'] = 'navigation';
   }
 }
diff --git a/core/modules/node/lib/Drupal/node/Plugin/Block/RecentContentBlock.php b/core/modules/node/lib/Drupal/node/Plugin/Block/RecentContentBlock.php
index bc0c2c1720cbe488eca05341cbbb02e1e52a8930..3712bff03c9c5c1ddbd0bfe428c0e122880d33dd 100644
--- a/core/modules/node/lib/Drupal/node/Plugin/Block/RecentContentBlock.php
+++ b/core/modules/node/lib/Drupal/node/Plugin/Block/RecentContentBlock.php
@@ -32,9 +32,9 @@ public function settings() {
   }
 
   /**
-   * Overrides \Drupal\block\BlockBase::blockAccess().
+   * Overrides \Drupal\block\BlockBase::access().
    */
-  public function blockAccess() {
+  public function access() {
     return user_access('access content');
   }
 
diff --git a/core/modules/node/lib/Drupal/node/Plugin/Block/SyndicateBlock.php b/core/modules/node/lib/Drupal/node/Plugin/Block/SyndicateBlock.php
index a0df392cb544513ce89fea3a99c13ac917964b49..56b3a19591b20390bd0bdcb837681e8f653e9d00 100644
--- a/core/modules/node/lib/Drupal/node/Plugin/Block/SyndicateBlock.php
+++ b/core/modules/node/lib/Drupal/node/Plugin/Block/SyndicateBlock.php
@@ -32,9 +32,9 @@ public function settings() {
   }
 
   /**
-   * Overrides \Drupal\block\BlockBase::blockAccess().
+   * Overrides \Drupal\block\BlockBase::access().
    */
-  public function blockAccess() {
+  public function access() {
     return user_access('access content');
   }
 
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeBlockFunctionalTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeBlockFunctionalTest.php
index 3beb9690e9624a50e6a1f8a3d04ca06f5dcf71ea..92e181c6ef5100a7e35440c22facddb1ebb21048 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeBlockFunctionalTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeBlockFunctionalTest.php
@@ -61,7 +61,7 @@ public function testRecentNodeBlock() {
     ));
 
     // Enable the recent content block with two items.
-    $block = $this->drupalPlaceBlock('node_recent_block', array('machine_name' => 'test_block'), array('block_count' => 2));
+    $block = $this->drupalPlaceBlock('node_recent_block', array('machine_name' => 'test_block', 'block_count' => 2));
 
     // Test that block is not visible without nodes.
     $this->drupalGet('');
@@ -106,7 +106,7 @@ public function testRecentNodeBlock() {
     $this->drupalLogin($this->adminUser);
 
     // Set the number of recent nodes to show to 10.
-    $block->set('settings', array('block_count' => 10));
+    $block->getPlugin()->setConfig('block_count', 10);
     $block->save();
 
     // Post an additional node.
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 7ba5d2322570901e11d961d49c9023c906482f22..06051690266ba1a12b8d2dd717b8cacb2e2f153a 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -1099,8 +1099,8 @@ function node_is_page(EntityInterface $node) {
  * Implements hook_preprocess_HOOK() for block.tpl.php.
  */
 function node_preprocess_block(&$variables) {
-  if ($variables['block']->module == 'node') {
-    switch ($variables['block']->id) {
+  if ($variables['configuration']['module'] == 'node') {
+    switch ($variables['elements']['#plugin_id']) {
       case 'node_syndicate_block':
         $variables['attributes']['role'] = 'complementary';
         break;
diff --git a/core/modules/openid/openid.module b/core/modules/openid/openid.module
index ad4da7b87ea037b01b51580d46140914f9850f1c..1be4734ca9492b471fd011566ee19036ff66d962 100644
--- a/core/modules/openid/openid.module
+++ b/core/modules/openid/openid.module
@@ -6,6 +6,7 @@
  */
 
 use Guzzle\Http\Exception\RequestException;
+use Drupal\block\BlockPluginInterface;
 
 /**
  * Implements hook_menu().
@@ -160,13 +161,13 @@ function openid_user_logout($account) {
 }
 
 /**
- * Implements hook_block_view_MODULE_DELTA_alter().
+ * Implements hook_block_view_BASE_BLOCK_ID_alter() for 'user_login_block'.
  *
  * Adds the OpenID login form to the user login block.
  *
  * @see \Drupal\user\Plugin\block\block\UserLoginBlock
  */
-function openid_block_view_user_login_block_alter(&$build, $block) {
+function openid_block_view_user_login_block_alter(array &$build, BlockPluginInterface $block) {
   // Only alter the block when it is non-empty, i.e. when no user is logged in.
   if (!isset($build['content']['user_login_form'])) {
     return;
diff --git a/core/modules/overlay/overlay.module b/core/modules/overlay/overlay.module
index db034f9e78aff94e848ca8e516d4ae090c4ff957..31289d5fda5cea2e11e66393f6b9279d79883b7a 100644
--- a/core/modules/overlay/overlay.module
+++ b/core/modules/overlay/overlay.module
@@ -7,6 +7,8 @@
 
 use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
+use Drupal\block\Plugin\Core\Entity\Block;
+use Drupal\user\Plugin\Core\Entity\User;
 
 /**
  * Implements hook_help().
@@ -453,7 +455,7 @@ function theme_overlay_disable_message($variables) {
 /**
  * Implements hook_block_access().
  */
-function overlay_block_access($block) {
+function overlay_block_access(Block $block, $operation, User $account, $langcode) {
   // If we are limiting rendering to a subset of page regions, hide all blocks
   // which appear in regions not on that list. Note that overlay_page_alter()
   // does a more comprehensive job of preventing unwanted regions from being
diff --git a/core/modules/search/lib/Drupal/search/Plugin/Block/SearchBlock.php b/core/modules/search/lib/Drupal/search/Plugin/Block/SearchBlock.php
index 032fb5a7d4c119f8765f224d49ef62aac955ed5e..1afbfae06f8e32d1c6a1def07c32b97b742646e2 100644
--- a/core/modules/search/lib/Drupal/search/Plugin/Block/SearchBlock.php
+++ b/core/modules/search/lib/Drupal/search/Plugin/Block/SearchBlock.php
@@ -23,9 +23,9 @@
 class SearchBlock extends BlockBase {
 
   /**
-   * Overrides \Drupal\block\BlockBase::blockAccess().
+   * Overrides \Drupal\block\BlockBase::access().
    */
-  public function blockAccess() {
+  public function access() {
     return user_access('search content');
   }
 
diff --git a/core/modules/search/search.module b/core/modules/search/search.module
index 6501a854f99a6afaa4007c44a3db93e19540187f..f31488be21b7804868eecc2665121105c54ddfdd 100644
--- a/core/modules/search/search.module
+++ b/core/modules/search/search.module
@@ -135,10 +135,10 @@ function search_permission() {
 }
 
 /**
- * Implements hook_preprocess_block().
+ * Implements hook_preprocess_HOOK() for block.tpl.php.
  */
 function search_preprocess_block(&$variables) {
-  if ($variables['block']->id == 'search_form_block') {
+  if ($variables['plugin_id'] == 'search_form_block') {
     $variables['attributes']['role'] = 'search';
     $variables['content_attributes']['class'][] = 'container-inline';
   }
diff --git a/core/modules/shortcut/shortcut.module b/core/modules/shortcut/shortcut.module
index c2c9b4af6a97089abf5205518adf81aba96c3267..ba7bacc55c92fc9e7f91c3dd61e4d45b0f1ceffe 100644
--- a/core/modules/shortcut/shortcut.module
+++ b/core/modules/shortcut/shortcut.module
@@ -454,7 +454,7 @@ function shortcut_renderable_links($shortcut_set = NULL) {
  * Implements hook_preprocess_HOOK() for block.tpl.php.
  */
 function shortcut_preprocess_block(&$variables) {
-  if ($variables['block']->module == 'shortcut') {
+  if ($variables['configuration']['module'] == 'shortcut') {
     $variables['attributes']['role'] = 'navigation';
   }
 }
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
index 35206135157010887c2331ee6bde02ec0d24cb67..76988fa1f868d2a33258d0ab08c8972f4d0d810f 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
@@ -342,8 +342,8 @@ protected function drupalCreateContentType($settings = array()) {
    *
    * @param string $plugin_id
    *   The plugin ID of the block type for this block instance.
-   * @param array $values
-   *   (optional) An associative array of values for the block entity.
+   * @param array $settings
+   *   (optional) An associative array of settings for the block entity.
    *   Override the defaults by specifying the key and value in the array, for
    *   example:
    *   @code
@@ -356,8 +356,7 @@ protected function drupalCreateContentType($settings = array()) {
    *   - machine_name: Random string.
    *   - region: 'sidebar_first'.
    *   - theme: The default theme.
-   * @param array $settings
-   *   (optional) An associative array of plugin-specific settings.
+   *   - visibility: Empty array.
    *
    * @return \Drupal\block\Plugin\Core\Entity\Block
    *   The block entity.
@@ -365,15 +364,20 @@ protected function drupalCreateContentType($settings = array()) {
    * @todo
    *   Add support for creating custom block instances.
    */
-  protected function drupalPlaceBlock($plugin_id, array $values = array(), array $settings = array()) {
-    $values += array(
+  protected function drupalPlaceBlock($plugin_id, array $settings = array()) {
+    $settings += array(
       'plugin' => $plugin_id,
-      'label' => $this->randomName(8),
       'region' => 'sidebar_first',
-      'theme' => config('system.theme')->get('default'),
       'machine_name' => strtolower($this->randomName(8)),
-      'settings' => $settings,
+      'theme' => config('system.theme')->get('default'),
+      'label' => $this->randomName(8),
+      'visibility' => array(),
     );
+    foreach (array('region', 'machine_name', 'theme', 'plugin', 'visibility') as $key) {
+      $values[$key] = $settings[$key];
+      unset($settings[$key]);
+    }
+    $values['settings'] = $settings;
     // Build the ID out of the theme and machine_name.
     $values['id'] = $values['theme'] . '.' . $values['machine_name'];
     $block = entity_create('block', $values);
diff --git a/core/modules/statistics/lib/Drupal/statistics/Plugin/Block/StatisticsPopularBlock.php b/core/modules/statistics/lib/Drupal/statistics/Plugin/Block/StatisticsPopularBlock.php
index 46e97b829e7124a0977ab58771ae7550f9bba1e3..6eebb8376b7e667b718d4c3118940f35371e824d 100644
--- a/core/modules/statistics/lib/Drupal/statistics/Plugin/Block/StatisticsPopularBlock.php
+++ b/core/modules/statistics/lib/Drupal/statistics/Plugin/Block/StatisticsPopularBlock.php
@@ -55,9 +55,9 @@ public function settings() {
   }
 
     /**
-   * Overrides \Drupal\block\BlockBase::blockAccess().
+   * Overrides \Drupal\block\BlockBase::access().
    */
-  public function blockAccess() {
+  public function access() {
     if (user_access('access content')) {
       $daytop = $this->configuration['top_day_num'];
       if (!$daytop || !($result = statistics_title_list('daycount', $daytop)) || !($this->day_list = node_title_list($result, t("Today's:")))) {
diff --git a/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsReportsTest.php b/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsReportsTest.php
index ed14bb0c8a5c6c25236eb731801d4a99cd0cb352..b897f993fe0c47180ce85a0a658005fcd0dc1280 100644
--- a/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsReportsTest.php
+++ b/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsReportsTest.php
@@ -41,7 +41,8 @@ function testPopularContentBlock() {
     $client->post($stats_path, $headers, $post)->send();
 
     // Configure and save the block.
-    $this->drupalPlaceBlock('statistics_popular_block', array('label' => 'Popular content'), array(
+    $this->drupalPlaceBlock('statistics_popular_block', array(
+      'label' => 'Popular content',
       'top_day_num' => 3,
       'top_all_num' => 3,
       'top_last_num' => 3,
diff --git a/core/modules/statistics/statistics.module b/core/modules/statistics/statistics.module
index 66842a5681e92594a6f6499986b272a8b12a128e..9d0c19eda66d6a577a61e15959ff71b3e23ec956 100644
--- a/core/modules/statistics/statistics.module
+++ b/core/modules/statistics/statistics.module
@@ -237,7 +237,7 @@ function statistics_update_index() {
  * Implements hook_preprocess_HOOK() for block.tpl.php.
  */
 function statistics_preprocess_block(&$variables) {
-  if ($variables['block']->module == 'statistics') {
+  if ($variables['configuration']['module'] == 'statistics') {
     $variables['attributes']['role'] = 'navigation';
   }
 }
diff --git a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemHelpBlock.php b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemHelpBlock.php
index 9e121127e807cf11ccb533ee0097505d34d3c54a..a370374789b5d07ba5478a09fb0e1aa884db1d87 100644
--- a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemHelpBlock.php
+++ b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemHelpBlock.php
@@ -30,9 +30,9 @@ class SystemHelpBlock extends BlockBase {
   protected $help;
 
   /**
-   * Overrides \Drupal\block\BlockBase::blockAccess().
+   * Overrides \Drupal\block\BlockBase::access().
    */
-  public function blockAccess() {
+  public function access() {
     $this->help = menu_get_active_help();
     return (bool) $this->help;
   }
diff --git a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMenuBlock.php b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMenuBlock.php
index dd31fe3c2cdb01aa4c14c042f3e4035825a9eaef..847249e0fbf8dd4866d9df4a195cbbfe0604edd0 100644
--- a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMenuBlock.php
+++ b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMenuBlock.php
@@ -24,9 +24,9 @@
 class SystemMenuBlock extends BlockBase {
 
   /**
-   * Overrides \Drupal\block\BlockBase::blockAccess().
+   * Overrides \Drupal\block\BlockBase::access().
    */
-  public function blockAccess() {
+  public function access() {
     // @todo The 'Tools' menu should be available to anonymous users.
     list($plugin, $derivative) = explode(':', $this->getPluginId());
     return ($GLOBALS['user']->uid || in_array($derivative, array('menu-main', 'menu-tools', 'menu-footer')));
diff --git a/core/modules/system/lib/Drupal/system/Tests/Upgrade/BlockUpgradePathTest.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/BlockUpgradePathTest.php
index b9129e36683ef7272056eb73655678e97e0fbca8..45f2efbfd24196118d3c316db4328cb879ab554f 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/BlockUpgradePathTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/BlockUpgradePathTest.php
@@ -42,16 +42,16 @@ public function testBlockUpgradeTitleLength() {
     // Add a block instance with a 255-character title.
     // Confirm that the custom block has been created, and title matches input.
     $settings = array(
-      'label' => $this->randomName(255),
+      'settings[label]' => $this->randomName(255),
       'machine_name' => strtolower($this->randomName(8)),
       'region' => 'sidebar_first',
     );
     $this->drupalPost('admin/structure/block/add/system_powered_by_block/' . config('system.theme')->get('default'), $settings, t('Save block'));
-    $this->assertText($settings['label'], 'Block with title longer than 64 characters successfully created.');
+    $this->assertText($settings['settings[label]'], 'Block with title longer than 64 characters successfully created.');
 
     // Try to add a block with a title over 255 characters.
     $settings = array(
-      'label' => $this->randomName(256),
+      'settings[label]' => $this->randomName(256),
       'machine_name' => strtolower($this->randomName(8)),
       'region' => 'sidebar_first',
     );
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index 614cec745d3c92bf31700f660007b541f81be10d..c75309c474de9b690310e4984ee18907f74a0192 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -2718,20 +2718,18 @@ function system_user_timezone(&$form, &$form_state) {
  * Implements hook_preprocess_HOOK() for block.tpl.php.
  */
 function system_preprocess_block(&$variables) {
-  switch ($variables['block']->id) {
+  // Derive the base plugin ID.
+  list($plugin_id) = explode(':', $variables['plugin_id'] . ':');
+  switch ($plugin_id) {
     case 'system_powered_by_block':
       $variables['attributes_array']['role'] = 'complementary';
       break;
     case 'system_help_block':
       $variables['attributes_array']['role'] = 'complementary';
       break;
-
-    // System menu blocks should get the same class as menu module blocks.
-    default:
-      if ($variables['elements']['#block']->getPlugin() instanceof SystemMenuBlock) {
-        $variables['attributes_array']['role'] = 'navigation';
-        $variables['classes_array'][] = 'block-menu';
-      }
+    case 'system_menu_block':
+      $variables['attributes']['role'] = 'navigation';
+      $variables['attributes']['classes'][] = 'block-menu';
   }
 }
 
diff --git a/core/modules/user/lib/Drupal/user/Plugin/Block/UserLoginBlock.php b/core/modules/user/lib/Drupal/user/Plugin/Block/UserLoginBlock.php
index 6f1486e6069f48781a850468ff907804c61dc2e9..dd890bdf17130973d69eaacb8d379678b09ef899 100644
--- a/core/modules/user/lib/Drupal/user/Plugin/Block/UserLoginBlock.php
+++ b/core/modules/user/lib/Drupal/user/Plugin/Block/UserLoginBlock.php
@@ -23,9 +23,9 @@
 class UserLoginBlock extends BlockBase {
 
   /**
-   * Overrides \Drupal\block\BlockBase::blockAccess().
+   * Overrides \Drupal\block\BlockBase::access().
    */
-  public function blockAccess() {
+  public function access() {
     return (!$GLOBALS['user']->uid && !(arg(0) == 'user' && !is_numeric(arg(1))));
   }
 
diff --git a/core/modules/user/lib/Drupal/user/Plugin/Block/UserNewBlock.php b/core/modules/user/lib/Drupal/user/Plugin/Block/UserNewBlock.php
index b9e1728ffe6922487e95c3e53d57532bd5d21c9a..41c2a437e330fb8a1e50aaffbe2e231c2b05b21b 100644
--- a/core/modules/user/lib/Drupal/user/Plugin/Block/UserNewBlock.php
+++ b/core/modules/user/lib/Drupal/user/Plugin/Block/UserNewBlock.php
@@ -35,9 +35,9 @@ public function settings() {
   }
 
   /**
-   * Overrides \Drupal\block\BlockBase::blockAccess().
+   * Overrides \Drupal\block\BlockBase::access().
    */
-  public function blockAccess() {
+  public function access() {
     return user_access('access content');
   }
 
diff --git a/core/modules/user/lib/Drupal/user/Plugin/Block/UserOnlineBlock.php b/core/modules/user/lib/Drupal/user/Plugin/Block/UserOnlineBlock.php
index cad0da085b1faf07ed7dd0d0baf8f0e50e943ebd..fbae351f55cc01bb1c37a3bb1e5fdca5aa79316c 100644
--- a/core/modules/user/lib/Drupal/user/Plugin/Block/UserOnlineBlock.php
+++ b/core/modules/user/lib/Drupal/user/Plugin/Block/UserOnlineBlock.php
@@ -39,9 +39,9 @@ public function settings() {
   }
 
   /**
-   * Overrides \Drupal\block\BlockBase::blockAccess().
+   * Overrides \Drupal\block\BlockBase::access().
    */
-  public function blockAccess() {
+  public function access() {
     return user_access('access content');
   }
 
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index ed3078cd98bdc657967475f103504b3530a5b84f..3ae6154a780568c2b0db992b4dc0d4a236569023 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -663,8 +663,8 @@ function user_validate_current_pass(&$form, &$form_state) {
  * Implements hook_preprocess_HOOK() for block.tpl.php.
  */
 function user_preprocess_block(&$variables) {
-  if ($variables['block']->module == 'user') {
-    switch ($variables['block']->id) {
+  if ($variables['configuration']['module'] == 'user') {
+    switch ($variables['elements']['#plugin_id']) {
       case 'user_login_block':
         $variables['attributes']['role'] = 'form';
         break;
diff --git a/core/modules/views/lib/Drupal/views/Plugin/Block/ViewsBlock.php b/core/modules/views/lib/Drupal/views/Plugin/Block/ViewsBlock.php
index 0d42a89ea8bc6039268c6c74a0cf8e72e25e7611..1e2bfd5ee025dd761720b1c1f94729a4148a3c55 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/Block/ViewsBlock.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/Block/ViewsBlock.php
@@ -8,7 +8,6 @@
 namespace Drupal\views\Plugin\Block;
 
 use Drupal\block\BlockBase;
-use Drupal\block\Plugin\Core\Entity\Block;
 use Drupal\Component\Annotation\Plugin;
 use Drupal\Core\Annotation\Translation;
 
@@ -41,8 +40,8 @@ class ViewsBlock extends BlockBase {
   /**
    * Overrides \Drupal\Component\Plugin\PluginBase::__construct().
    */
-  public function __construct(array $configuration, $plugin_id, array $plugin_definition, Block $entity) {
-    parent::__construct($configuration, $plugin_id, $plugin_definition, $entity);
+  public function __construct(array $configuration, $plugin_id, array $plugin_definition) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
 
     list($plugin, $delta) = explode(':', $this->getPluginId());
     list($name, $this->displayID) = explode('-', $delta, 2);
@@ -52,9 +51,9 @@ public function __construct(array $configuration, $plugin_id, array $plugin_defi
   }
 
   /**
-   * Overrides \Drupal\block\BlockBase::blockAccess().
+   * Overrides \Drupal\block\BlockBase::access().
    */
-  public function blockAccess() {
+  public function access() {
     return $this->view->access($this->displayID);
   }
 
@@ -76,7 +75,7 @@ public function form($form, &$form_state) {
   protected function blockBuild() {
     $output = $this->view->executeDisplay($this->displayID);
     // Set the label to the title configured in the view.
-    $this->entity->set('label', filter_xss_admin($this->view->getTitle()));
+    $this->configuration['label'] = filter_xss_admin($this->view->getTitle());
     // Before returning the block output, convert it to a renderable array
     // with contextual links.
     $this->addContextualLinks($output);
diff --git a/core/modules/views/views.module b/core/modules/views/views.module
index 581c04b8bee08cd10a9c5dbbf303f342dd67614d..02d7791c8fcffac8c2e517f8fc4f389aa9d41fe5 100644
--- a/core/modules/views/views.module
+++ b/core/modules/views/views.module
@@ -560,7 +560,7 @@ function views_contextual_links_view_alter(&$element, $items) {
  * @param $display_id
  *   The ID of the display within $view whose contextual links will be added.
  *
- * @see views_block_view()
+ * @see \Drupal\views\Plugin\block\block\ViewsBlock::addContextualLinks()
  * @see views_page_alter()
  * @see template_preprocess_views_view()
  */
diff --git a/core/profiles/minimal/config/block.block.stark.admin.yml b/core/profiles/minimal/config/block.block.stark.admin.yml
index e84cdbee1fce13e243f7a688439fb41b5356f890..d67096fc1baf81c11831322192551f1d88d94c24 100644
--- a/core/profiles/minimal/config/block.block.stark.admin.yml
+++ b/core/profiles/minimal/config/block.block.stark.admin.yml
@@ -1,9 +1,14 @@
 id: stark.admin
-label: Administration
-region: sidebar_first
 weight: '1'
-module: system
 status: '1'
+langcode: en
+region: sidebar_first
+plugin: 'system_menu_block:menu-admin'
+settings:
+  label: Administration
+  module: system
+  label_display: visible
+  cache: '-1'
 visibility:
   path:
     visibility: '0'
@@ -13,7 +18,3 @@ visibility:
   node_type:
     types: {  }
   visibility__active_tab: edit-visibility-path
-plugin: 'system_menu_block:menu-admin'
-settings:
-  cache: '-1'
-label_display: visible
diff --git a/core/profiles/minimal/config/block.block.stark.login.yml b/core/profiles/minimal/config/block.block.stark.login.yml
index ba8a66dacd38eb442fa01a6dca7b213f6c976374..b15e39593c9ef5f858c8fa0f0ec7267f4574f818 100644
--- a/core/profiles/minimal/config/block.block.stark.login.yml
+++ b/core/profiles/minimal/config/block.block.stark.login.yml
@@ -1,9 +1,14 @@
 id: stark.login
-label: 'User login'
-region: sidebar_first
 weight: '0'
-module: user
 status: '1'
+langcode: en
+region: sidebar_first
+plugin: user_login_block
+settings:
+  label: 'User login'
+  module: user
+  label_display: visible
+  cache: '-1'
 visibility:
   path:
     visibility: '0'
@@ -13,7 +18,3 @@ visibility:
   node_type:
     types: {  }
   visibility__active_tab: edit-visibility-path
-plugin: user_login_block
-settings:
-  cache: '-1'
-label_display: visible
diff --git a/core/profiles/minimal/config/block.block.stark.tools.yml b/core/profiles/minimal/config/block.block.stark.tools.yml
index dda5b98827eb52ce44a48bbbb7000e48fc0aa239..6901d44ce90c7fdf093e4e1c0a0f6a8c366e02c6 100644
--- a/core/profiles/minimal/config/block.block.stark.tools.yml
+++ b/core/profiles/minimal/config/block.block.stark.tools.yml
@@ -1,9 +1,14 @@
 id: stark.tools
-label: Tools
-region: sidebar_first
 weight: '0'
-module: system
 status: '1'
+langcode: en
+region: sidebar_first
+plugin: 'system_menu_block:menu-tools'
+settings:
+  label: Tools
+  module: system
+  label_display: visible
+  cache: '-1'
 visibility:
   path:
     visibility: '0'
@@ -13,7 +18,3 @@ visibility:
   node_type:
     types: {  }
   visibility__active_tab: edit-visibility-path
-plugin: 'system_menu_block:menu-tools'
-settings:
-  cache: '-1'
-label_display: visible
diff --git a/core/profiles/standard/config/block.block.bartik.content.yml b/core/profiles/standard/config/block.block.bartik.content.yml
index 07c3cdd0aea6e1ed925aed04ed5a669be95e71f7..24b161c27a5afdee7a9d279b96751ec20fa75b11 100644
--- a/core/profiles/standard/config/block.block.bartik.content.yml
+++ b/core/profiles/standard/config/block.block.bartik.content.yml
@@ -1,7 +1,13 @@
 id: bartik.content
-plugin: system_main_block
+weight: '0'
 status: '1'
+langcode: en
+region: content
+plugin: system_main_block
 settings:
+  label: 'Main page content'
+  module: system
+  label_display: '0'
   cache: '-1'
 visibility:
   path:
@@ -14,9 +20,3 @@ visibility:
       article: '0'
       page: '0'
   visibility__active_tab: edit-visibility-path
-label: ''
-module: system
-region: content
-weight: '0'
-langcode: en
-label_display: visible
diff --git a/core/profiles/standard/config/block.block.bartik.footer.yml b/core/profiles/standard/config/block.block.bartik.footer.yml
index 553edb7dd8c655a5b74fde6c1e346a916ad9dcaa..65c77f01df5e9f9cb886e591db314739cd3bf9b3 100644
--- a/core/profiles/standard/config/block.block.bartik.footer.yml
+++ b/core/profiles/standard/config/block.block.bartik.footer.yml
@@ -1,9 +1,14 @@
 id: bartik.footer
-plugin: 'system_menu_block:menu-footer'
+weight: '0'
 status: '1'
+langcode: en
+region: footer
+plugin: 'system_menu_block:menu-footer'
 settings:
+  label: 'Footer menu'
+  module: system
+  label_display: visible
   cache: '-1'
-label: 'Footer menu'
 visibility:
   path:
     visibility: '0'
@@ -15,8 +20,3 @@ visibility:
       article: '0'
       page: '0'
   visibility__active_tab: edit-visibility-path
-module: system
-region: footer
-weight: '0'
-langcode: en
-label_display: visible
diff --git a/core/profiles/standard/config/block.block.bartik.help.yml b/core/profiles/standard/config/block.block.bartik.help.yml
index 84395a6f7a2b571487f3146371d7c3ffef4533fd..11f7ec6a8e9d0c6de8bace08f89d2e78747c118b 100644
--- a/core/profiles/standard/config/block.block.bartik.help.yml
+++ b/core/profiles/standard/config/block.block.bartik.help.yml
@@ -1,7 +1,13 @@
 id: bartik.help
-plugin: system_help_block
+weight: '0'
 status: '1'
+langcode: en
+region: help
+plugin: system_help_block
 settings:
+  label: 'System Help'
+  module: system
+  label_display: '0'
   cache: '-1'
 visibility:
   path:
@@ -14,9 +20,3 @@ visibility:
       article: '0'
       page: '0'
   visibility__active_tab: edit-visibility-path
-label: ''
-module: system
-region: help
-weight: '0'
-langcode: en
-label_display: visible
diff --git a/core/profiles/standard/config/block.block.bartik.login.yml b/core/profiles/standard/config/block.block.bartik.login.yml
index aac6997b6107b85219da455935c8514cbfc15d39..69e7f9b64df993199b930892ae73f737a8271380 100644
--- a/core/profiles/standard/config/block.block.bartik.login.yml
+++ b/core/profiles/standard/config/block.block.bartik.login.yml
@@ -1,7 +1,13 @@
 id: bartik.login
-whois_new_count: '5'
+weight: '0'
 status: '1'
+langcode: en
+region: sidebar_first
+plugin: user_login_block
 settings:
+  label: 'User login'
+  module: user
+  label_display: visible
   cache: '-1'
 visibility:
   path:
@@ -14,10 +20,3 @@ visibility:
       article: '0'
       page: '0'
   visibility__active_tab: edit-visibility-path
-label: 'User login'
-module: user
-region: sidebar_first
-weight: '0'
-plugin: user_login_block
-langcode: en
-label_display: visible
diff --git a/core/profiles/standard/config/block.block.bartik.powered.yml b/core/profiles/standard/config/block.block.bartik.powered.yml
index 48424f8ab9f569c56be40531e5ea0c1c4c5f7121..a8de9406c3c144b287bf2b2955320cd55aa61e34 100644
--- a/core/profiles/standard/config/block.block.bartik.powered.yml
+++ b/core/profiles/standard/config/block.block.bartik.powered.yml
@@ -1,7 +1,13 @@
 id: bartik.powered
-plugin: system_powered_by_block
+weight: '10'
 status: '1'
+langcode: en
+region: footer
+plugin: system_powered_by_block
 settings:
+  label: 'Powered by Drupal'
+  module: system
+  label_display: '0'
   cache: '-1'
 visibility:
   path:
@@ -14,9 +20,3 @@ visibility:
       article: '0'
       page: '0'
   visibility__active_tab: edit-visibility-path
-label: ''
-module: system
-region: footer
-weight: '10'
-langcode: en
-label_display: visible
diff --git a/core/profiles/standard/config/block.block.bartik.search.yml b/core/profiles/standard/config/block.block.bartik.search.yml
index bcf0249a907f1735554f90b7e16bfe5f800c78b7..18f6a7c702e1a84f4a5027953812ddbec1274cb6 100644
--- a/core/profiles/standard/config/block.block.bartik.search.yml
+++ b/core/profiles/standard/config/block.block.bartik.search.yml
@@ -1,7 +1,13 @@
 id: bartik.search
-plugin: search_form_block
+weight: '-1'
 status: '1'
+langcode: en
+region: sidebar_first
+plugin: search_form_block
 settings:
+  label: Search
+  module: search
+  label_display: visible
   cache: '-1'
 visibility:
   path:
@@ -14,9 +20,3 @@ visibility:
       article: '0'
       page: '0'
   visibility__active_tab: edit-visibility-path
-label: 'Search'
-module: search
-region: sidebar_first
-weight: '-1'
-langcode: en
-label_display: visible
diff --git a/core/profiles/standard/config/block.block.bartik.tools.yml b/core/profiles/standard/config/block.block.bartik.tools.yml
index 56c8ba45901c3995791d01acad2d5037943abdcd..633e299ccfc712123992a774c6f4a70c1081b5a0 100644
--- a/core/profiles/standard/config/block.block.bartik.tools.yml
+++ b/core/profiles/standard/config/block.block.bartik.tools.yml
@@ -1,7 +1,13 @@
 id: bartik.tools
-plugin: 'system_menu_block:menu-tools'
+weight: '0'
 status: '1'
+langcode: en
+region: sidebar_first
+plugin: 'system_menu_block:menu-tools'
 settings:
+  label: Tools
+  module: system
+  label_display: visible
   cache: '-1'
 visibility:
   path:
@@ -14,9 +20,3 @@ visibility:
       article: '0'
       page: '0'
   visibility__active_tab: edit-visibility-path
-label: 'Tools'
-module: system
-region: sidebar_first
-weight: '0'
-langcode: en
-label_display: visible
diff --git a/core/profiles/standard/config/block.block.seven.content.yml b/core/profiles/standard/config/block.block.seven.content.yml
index f14f147942f07d7d3ee16459f4184611535114cc..172580070f2ac32410375fbaf59e9b38db1c128d 100644
--- a/core/profiles/standard/config/block.block.seven.content.yml
+++ b/core/profiles/standard/config/block.block.seven.content.yml
@@ -1,7 +1,13 @@
 id: seven.content
-plugin: system_main_block
+weight: '0'
 status: '1'
+langcode: en
+region: content
+plugin: system_main_block
 settings:
+  label: 'Main page content'
+  module: system
+  label_display: '0'
   cache: '-1'
 visibility:
   path:
@@ -14,9 +20,3 @@ visibility:
       article: '0'
       page: '0'
   visibility__active_tab: edit-visibility-path
-label: ''
-module: system
-region: content
-weight: '0'
-langcode: en
-label_display: visible
diff --git a/core/profiles/standard/config/block.block.seven.help.yml b/core/profiles/standard/config/block.block.seven.help.yml
index 075f518bcceca464e80fe56f63cf6b76cd397169..132ee4570e920ff9f10360446df71168acfeab17 100644
--- a/core/profiles/standard/config/block.block.seven.help.yml
+++ b/core/profiles/standard/config/block.block.seven.help.yml
@@ -1,7 +1,13 @@
 id: seven.help
-plugin: system_help_block
+weight: '0'
 status: '1'
+langcode: en
+region: help
+plugin: system_help_block
 settings:
+  label: 'System Help'
+  module: system
+  label_display: '0'
   cache: '-1'
 visibility:
   path:
@@ -14,9 +20,3 @@ visibility:
       article: '0'
       page: '0'
   visibility__active_tab: edit-visibility-path
-label: ''
-module: system
-region: help
-weight: '0'
-langcode: en
-label_display: visible
diff --git a/core/profiles/standard/config/block.block.seven.login.yml b/core/profiles/standard/config/block.block.seven.login.yml
index f0fb2b257be0e55533d0dbd5445a451c5e6ff4c7..8ec166182b5d57163fe555f082469ec0a5ca9897 100644
--- a/core/profiles/standard/config/block.block.seven.login.yml
+++ b/core/profiles/standard/config/block.block.seven.login.yml
@@ -1,7 +1,13 @@
 id: seven.login
-plugin: user_login_block
+weight: '10'
 status: '1'
+langcode: en
+region: content
+plugin: user_login_block
 settings:
+  label: 'User login'
+  module: user
+  label_display: visible
   cache: '-1'
 visibility:
   path:
@@ -14,9 +20,4 @@ visibility:
       article: '0'
       page: '0'
   visibility__active_tab: edit-visibility-path
-label: 'User login'
-module: user
-region: content
-weight: '10'
-langcode: en
-label_display: visible
+