diff --git a/core/modules/block/block.admin.inc b/core/modules/block/block.admin.inc
index 13f17ad..2c57578 100644
--- a/core/modules/block/block.admin.inc
+++ b/core/modules/block/block.admin.inc
@@ -56,7 +56,7 @@ function block_admin_display_prepare_blocks($theme) {
   $blocks = _block_rehash($theme);
   $compare_theme = &drupal_static('_block_compare:theme');
   $compare_theme = $theme;
-  usort($blocks, '_block_compare');
+  uasort($blocks, '_block_compare');
   return $blocks;
 }
 
@@ -115,11 +115,6 @@ function block_admin_display_form($form, &$form_state, $blocks, $theme, $block_r
   $form['#tree'] = TRUE;
 
   foreach ($blocks as $key => $instance) {
-    $block = $instance->getConfig();
-    $form['blocks'][$key]['config_id'] = array(
-      '#type' => 'value',
-      '#value' => $block['config_id'],
-    );
     $info = $instance->getDefinition();
     $form['blocks'][$key]['info'] = array(
       '#markup' => check_plain($info['subject']),
@@ -130,14 +125,14 @@ function block_admin_display_form($form, &$form_state, $blocks, $theme, $block_r
     );
     $form['blocks'][$key]['weight'] = array(
       '#type' => 'weight',
-      '#default_value' => $block['weight'],
+      '#default_value' => $instance->get('weight'),
       '#delta' => $weight_delta,
       '#title_display' => 'invisible',
       '#title' => t('Weight for @block block', array('@block' => $info['subject'])),
     );
     $form['blocks'][$key]['region'] = array(
       '#type' => 'select',
-      '#default_value' => $block['region'] != BLOCK_REGION_NONE ? $block['region'] : NULL,
+      '#default_value' => $instance->get('region') != BLOCK_REGION_NONE ? $instance->get('region') : NULL,
       '#empty_value' => BLOCK_REGION_NONE,
       '#title_display' => 'invisible',
       '#title' => t('Region for @block block', array('@block' => $info['subject'])),
@@ -145,11 +140,11 @@ function block_admin_display_form($form, &$form_state, $blocks, $theme, $block_r
     );
     $links['configure'] = array(
       'title' => t('configure'),
-      'href' => 'admin/structure/block/manage/' . $block['config_id'] . '/' . $theme . '/configure',
+      'href' => 'admin/structure/block/manage/' . $key . '/' . $theme . '/configure',
     );
     $links['delete'] = array(
       'title' => t('delete'),
-      'href' => 'admin/structure/block/manage/' . $block['config_id'] . '/' . $theme . '/delete',
+      'href' => 'admin/structure/block/manage/' . $key . '/' . $theme . '/delete',
     );
     $form['blocks'][$key]['operations'] = array(
       '#type' => 'operations',
@@ -180,11 +175,11 @@ function block_admin_display_form($form, &$form_state, $blocks, $theme, $block_r
  * @see block_admin_display_form()
  */
 function block_admin_display_form_submit($form, &$form_state) {
-  foreach ($form_state['values']['blocks'] as $block) {
-    $config = config($block['config_id']);
-    $config->set('weight', $block['weight']);
-    $config->set('region', $block['region']);
-    $config->save();
+  $blocks = entity_load_multiple('block', array_keys($form_state['values']['blocks']));
+  foreach ($blocks as $block_id => $block) {
+    $block->set('weight', $form_state['values']['blocks'][$block_id]['weight']);
+    $block->set('region', $form_state['values']['blocks'][$block_id]['region']);
+    $block->save();
   }
   drupal_set_message(t('The block settings have been updated.'));
   cache_invalidate_tags(array('content' => TRUE));
@@ -195,10 +190,8 @@ function block_admin_display_form_submit($form, &$form_state) {
  *
  * Callback for usort() in block_admin_display_prepare_blocks().
  */
-function _block_compare($ainstance, $binstance) {
+function _block_compare($a, $b) {
   global $theme_key;
-  $a = $ainstance->getConfig();
-  $b = $binstance->getConfig();
 
   // Theme should be set before calling this function, or the current theme
   // is being used.
@@ -215,24 +208,26 @@ function _block_compare($ainstance, $binstance) {
   }
 
   // Separate enabled from disabled.
-  $status = $b['status'] - $a['status'];
+  $status = $b->get('status') - $a->get('status');
   if ($status) {
     return $status;
   }
   // Sort by region (in the order defined by theme .info file).
-  if ((!empty($a['region']) && !empty($b['region'])) && ($place = ($regions[$a['region']] - $regions[$b['region']]))) {
+  $aregion = $a->get('region');
+  $bregion = $b->get('region');
+  if ((!empty($aregion) && !empty($bregion)) && ($place = ($regions[$aregion] - $regions[$bregion]))) {
     return $place;
   }
   // Sort by weight, unless disabled.
-  if ($a['region'] != BLOCK_REGION_NONE) {
-    $weight = $a['weight'] - $b['weight'];
+  if ($a->get('region') != BLOCK_REGION_NONE) {
+    $weight = $a->get('weight') - $b->get('weight');
     if ($weight) {
       return $weight;
     }
   }
   // Sort by title.
-  $ainfo = $ainstance->getDefinition();
-  $binfo = $binstance->getDefinition();
+  $ainfo = $a->getDefinition();
+  $binfo = $b->getDefinition();
   return strcmp($ainfo['subject'], $binfo['subject']);
 }
 
@@ -252,22 +247,9 @@ function _block_compare($ainstance, $binstance) {
  *
  * @ingroup forms
  */
-function block_admin_configure($form, &$form_state, $plugin_id, $theme = NULL) {
-  $instance = block_load($plugin_id);
-  $form['#instance'] = $instance;
-  $config = $instance->getConfig();
-  if (!isset($config['config_id']) && !$theme) {
-    $theme = variable_get('theme_default', 'stark');
-  }
-  elseif (!$theme && isset($config['config_id'])) {
-    list(, , , $theme) = explode('.', $config['config_id']);
-  }
-  $form['theme'] = array(
-    '#type' => 'value',
-    '#value' => $theme,
-  );
-  $form += $instance->form($form, $form_state);
-  return $form;
+function block_admin_configure($plugin_id, $theme = NULL) {
+  $instance = block_load($plugin_id, array('theme' => $theme));
+  return entity_get_form($instance);
 }
 
 /**
@@ -288,14 +270,6 @@ function block_admin_configure_validate($form, &$form_state) {
  */
 function block_admin_configure_submit($form, &$form_state) {
   $form['#instance']->submit($form, $form_state);
-  $config_values = $form['#instance']->getConfig();
-  $machine_name = 'plugin.core.block.' . $form_state['values']['theme'] . '.' . $form_state['values']['machine_name'];
-  $config = config($machine_name);
-  $config->set('id', $form['#instance']->getPluginId());
-  foreach ($config_values as $key => $value) {
-    $config->set($key, $value);
-  }
-  $config->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:' . $form_state['values']['theme'];
diff --git a/core/modules/block/block.module b/core/modules/block/block.module
index 31ef8db..9ae4d0c 100644
--- a/core/modules/block/block.module
+++ b/core/modules/block/block.module
@@ -121,8 +121,8 @@ function block_menu() {
   );
   $items['admin/structure/block/manage/%/%'] = array(
     'title' => 'Configure block',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('block_admin_configure', 4, 5),
+    'page callback' => 'block_admin_configure',
+    'page arguments' => array(4, 5),
     'access arguments' => array('administer blocks'),
     'file' => 'block.admin.inc',
   );
@@ -304,15 +304,13 @@ function _block_get_renderable_region($list = array()) {
     !in_array($_SERVER['REQUEST_METHOD'], array('GET', 'HEAD'));
 
   foreach ($list as $key => $block) {
-    $config = $block->getConfig();
-    $definition = $block->getDefinition();
     $build[$key] = array(
       '#block' => $block,
-      '#weight' => (int) $config['weight'],
+      '#weight' => $block->get('weight'),
       '#theme_wrappers' => array('block'),
     );
 
-    if ($not_cacheable || in_array($config['cache'], array(DRUPAL_NO_CACHE, DRUPAL_CACHE_CUSTOM))) {
+    if ($not_cacheable || in_array($block->get('cache'), array(DRUPAL_NO_CACHE, DRUPAL_CACHE_CUSTOM))) {
       // Non-cached blocks get built immediately. Provides more content
       // that can be easily manipulated during hook_page_alter().
       $build[$key] = _block_get_renderable_block($build[$key]);
@@ -323,8 +321,8 @@ function _block_get_renderable_region($list = array()) {
       $build[$key] += array(
         '#pre_render' => array('_block_get_renderable_block'),
         '#cache' => array(
-          'keys' => array($id, $config['module']),
-          'granularity' => $config['cache'],
+          'keys' => array($id, $block->get('module')),
+          'granularity' => $block->get('cache'),
           'bin' => 'block',
           'tags' => array('content' => TRUE),
         ),
@@ -336,7 +334,7 @@ function _block_get_renderable_region($list = array()) {
     // skip the help block, since we assume that most users do not need or want
     // to perform contextual actions on the help block, and the links needlessly
     // draw attention on it.
-    if ($definition['class'] != 'Drupal\\system\\Plugin\\block\\block\\SystemHelpBlock' && $definition['class'] != 'Drupal\\system\\Plugin\\block\\block\\SystemMainBlock') {
+    if (!in_array($block->getPluginId(), array('system_help_block', 'system_main_block'))) {
       global $theme;
       $build[$key]['#contextual_links']['block'] = array('admin/structure/block/manage', array($key, $theme));
     }
@@ -358,7 +356,14 @@ function _block_rehash($theme = NULL) {
   $blocks = array();
   $instances = array();
   $theme = $theme ? $theme : variable_get('theme_default', 'stark');
-  $block_configs = config_get_storage_names_with_prefix('plugin.core.block.' . $theme);
+  $foo = array();
+  foreach (entity_load_multiple('block') as $entity_id => $entity) {
+    if (strpos($entity_id, $theme . '.') === 0) {
+      $foo[$entity_id] = $entity;
+    }
+  }
+  return $foo;
+  $block_configs = config_get_storage_names_with_prefix('block.block.' . $theme);
   $regions = system_region_list($theme);
   foreach ($block_configs as $config) {
     $blocks[$config] = block_load($config);
@@ -466,19 +471,19 @@ function block_list($region) {
  *
  * @param string $plugin_id
  *   The plugin ID to load.
- * @param array $conf
+ * @param array $values
  *   An optional configuration array for creating a block instance manually
  *   rather than retrieving it from the configuration system.
  *
  * @return
  *   A block object.
  */
-function block_load($plugin_id, array $conf = array()) {
-  $manager = drupal_container()->get('plugin.manager.block');
-  if (!$block = $manager->getInstance(array('config' => $plugin_id))) {
-    $block = $manager->createInstance($plugin_id, $conf);
+function block_load($plugin_id, array $values = array()) {
+  if ($entity = entity_load('block', str_replace('block.block.', '', $plugin_id))) {
+    return $entity;
   }
-  return $block;
+  $values['pluginID'] = $plugin_id;
+  return entity_create('block', $values);
 }
 
 /**
@@ -490,12 +495,10 @@ function block_load($plugin_id, array $conf = array()) {
 function _block_load_blocks() {
   global $theme;
   $blocks = array();
-  $instances = config_get_storage_names_with_prefix('plugin.core.block.' . $theme);
-  $manager = drupal_container()->get('plugin.manager.block');
-  foreach ($instances as $plugin_id) {
-    $block = $manager->getInstance(array('config' => $plugin_id));
-    $config = $block->getConfig();
-    $blocks[$config['region']]["$plugin_id"] = $block;
+  foreach (entity_load_multiple('block') as $entity_id => $entity) {
+    if (strpos($entity_id, $theme . '.') === 0) {
+      $blocks[$entity->get('region')][$entity_id] = $entity;
+    }
   }
   return $blocks;
 }
@@ -515,7 +518,7 @@ function _block_get_renderable_block($element) {
   $block = $element['#block'];
   // Don't bother to build blocks that aren't accessible.
   if ($element['#access'] = $block->access()) {
-    $build = $block->build();
+    $build = $block->getPlugin()->build();
     if ($build) {
       if (isset($build['#title'])) {
         $element['#title'] = $build['#title'];
@@ -567,7 +570,7 @@ function block_rebuild() {
  */
 function template_preprocess_block(&$variables) {
   $block_counter = &drupal_static(__FUNCTION__, array());
-  $variables['block'] = (object) array_merge($variables['elements']['#block']->getDefinition(), $variables['elements']['#block']->getConfig());
+  $variables['block'] = (object) $variables['elements']['#block']->getDefinition();
   if (!empty($variables['elements']['#title']) && empty($variables['block']->subject)) {
     $variables['block']->subject = $variables['elements']['#title'];
   }
@@ -606,12 +609,10 @@ function template_preprocess_block(&$variables) {
     $variables['theme_hook_suggestions'][] = $suggestion .= '__' . strtr($part, '-', '_');
   }
   // Create a valid HTML ID and make sure it is unique.
-  if (!empty($variables['block']->config_id)) {
-    $config_id = explode('.', $variables['block']->config_id);
-    $machine_name = array_pop($config_id);
-    $variables['block_html_id'] = drupal_html_id('block-' . $machine_name);
-    $variables['theme_hook_suggestions'][] = 'block__' . $machine_name;
-  }
+  $config_id = explode('.', $variables['elements']['#block']->id());
+  $machine_name = array_pop($config_id);
+  $variables['block_html_id'] = drupal_html_id('block-' . $machine_name);
+  $variables['theme_hook_suggestions'][] = 'block__' . $machine_name;
 }
 
 /**
@@ -658,21 +659,6 @@ function block_admin_paths() {
 }
 
 /**
- * Implements hook_modules_uninstalled().
- *
- * Cleans up any block configuration for uninstalled modules.
- */
-function block_modules_uninstalled($modules) {
-  $block_configs = config_get_storage_names_with_prefix('plugin.core.block');
-  foreach ($block_configs as $config_id) {
-    $config = config($config_id);
-    if (in_array($config->get('module'), $modules)) {
-      $config->delete();
-    }
-  }
-}
-
-/**
  * Implements hook_language_delete().
  *
  * Delete the potential block visibility settings of the deleted language.
diff --git a/core/modules/block/lib/Drupal/block/BlockBase.php b/core/modules/block/lib/Drupal/block/BlockBase.php
index b8f770d..b226ca9 100644
--- a/core/modules/block/lib/Drupal/block/BlockBase.php
+++ b/core/modules/block/lib/Drupal/block/BlockBase.php
@@ -19,6 +19,22 @@
 abstract class BlockBase extends PluginBase implements BlockInterface {
 
   /**
+   * @todo.
+   *
+   * @var @todo.
+   */
+  protected $entity;
+
+  /**
+   * @todo.
+   */
+  public function init($entity) {
+    $this->entity = $entity;
+    // @todo.
+    $this->configuration += $entity->getDefinition();
+  }
+
+  /**
    * Implements \Drupal\block\BlockInterface::settings().
    *
    * Most block plugins should not override this method. To add additional
@@ -118,313 +134,6 @@ public function blockAccess() {
   }
 
   /**
-   * Implements \Drupal\block\BlockInterface::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.
-   *
-   * @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 (empty($this->configuration['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.
-    if (!empty($this->configuration['visibility']['role']['roles']) && !array_intersect(array_filter($this->configuration['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($this->configuration['visibility']['path']['visibility']) && $this->configuration['visibility']['path']['visibility'] == BLOCK_VISIBILITY_LISTED && empty($this->configuration['visibility']['path']['pages'])) {
-      return FALSE;
-    }
-
-    // Match path if necessary.
-    if (!empty($this->configuration['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($this->configuration['visibility']['path']['pages']);
-      if ($this->configuration['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 = !($this->configuration['visibility']['path']['visibility'] xor $page_match);
-      }
-      elseif (module_exists('php')) {
-        $page_match = php_eval($this->configuration['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($this->configuration['visibility']['language']['langcodes']) && array_filter($this->configuration['visibility']['language']['langcodes'])) {
-      if (empty($this->configuration['visibility']['language']['langcodes'][language($this->configuration['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) === FALSE) {
-        return FALSE;
-      }
-    }
-
-    // If nothing denied access to the block, it is accessible.
-    return TRUE;
-  }
-
-  /**
-   * Implements \Drupal\block\BlockInterface::form().
-   *
-   * Creates a generic configuration form for all block types. Individual
-   * block plugins can add elements to this form by overriding
-   * BlockBase::blockForm(). Most block plugins should not override this
-   * method unless they need to alter the generic form elements.
-   *
-   * @see \Drupal\block\BlockBase::blockForm()
-   */
-  public function form($form, &$form_state) {
-    $definition = $this->getDefinition();
-    $config = $this->getConfig();
-    $form['id'] = array(
-      '#type' => 'value',
-      '#value' => $definition['id'],
-    );
-    $form['module'] = array(
-      '#type' => 'value',
-      '#value' => $definition['module'],
-    );
-
-    // Get the block subject for the page title.
-    $subject = isset($config['subject']) ? $config['subject'] : '';
-
-    // Get the theme for the page title.
-    $theme_default = variable_get('theme_default', 'stark');
-    $admin_theme = config('system.theme')->get('admin');
-    $themes = list_themes();
-    $theme_key = $form['theme']['#value'];
-    $theme = $themes[$theme_key];
-    // Use meaningful titles for the main site and administrative themes.
-    $theme_title = $theme->info['name'];
-    if ($theme_key == $theme_default) {
-      $theme_title = t('!theme (default theme)', array('!theme' => $theme_title));
-    }
-    elseif ($admin_theme && $theme_key == $admin_theme) {
-      $theme_title = t('!theme (administration theme)', array('!theme' => $theme_title));
-    }
-
-    if ($subject) {
-      drupal_set_title(t("%subject block in %theme", array('%subject' => $subject, '%theme' => $theme_title)), PASS_THROUGH);
-    }
-
-    $form['settings'] = array(
-      '#weight' => -5,
-    );
-    $form['settings']['title'] = array(
-      '#type' => 'textfield',
-      '#title' => t('Block title'),
-      '#maxlength' => 255,
-      '#default_value' => isset($subject) ? $subject : '',
-    );
-    $form['settings']['machine_name'] = array(
-      '#type' => 'textfield',
-      '#title' => t('Block machine name'),
-      '#maxlength' => 64,
-      '#description' => t('A unique name to save this block configuration. Must be alpha-numeric and be underscore separated.'),
-      '#default_value' => isset($config['config_id']) ? $config['config_id'] : '',
-      '#required' => TRUE,
-    );
-    if (isset($config['config_id'])) {
-      $form['settings']['machine_name']['#disabled'] = TRUE;
-    }
-
-    // Region settings.
-    $form['region'] = array(
-      '#type' => 'select',
-      '#title' => t('Region'),
-      '#description' => t('Select the region where this block should be displayed.'),
-      '#default_value' => !empty($config['region']) && $config['region'] != -1 ? $config['region'] : NULL,
-      '#empty_value' => BLOCK_REGION_NONE,
-      '#options' => system_region_list($theme_key, REGIONS_VISIBLE),
-    );
-
-
-    // Visibility settings.
-    $form['visibility_title'] = array(
-      '#type' => 'item',
-      '#title' => t('Visibility settings'),
-      '#weight' => 10,
-    );
-    $form['visibility'] = array(
-      '#type' => 'vertical_tabs',
-      '#attached' => array(
-        'js' => array(drupal_get_path('module', 'block') . '/block.js'),
-      ),
-      '#tree' => TRUE,
-      '#weight' => 15,
-    );
-
-    // 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.
-    $access = user_access('use PHP for settings');
-    if (!empty($config['visibility']['path']['visibility']) && $config['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($config['visibility']['path']['pages']) ? $config['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($this->configuration['visibility']['path']['visibility']) ? $this->configuration['visibility']['path']['visibility'] : BLOCK_VISIBILITY_NOTLISTED,
-      );
-      $form['visibility']['path']['pages'] = array(
-        '#type' => 'textarea',
-        '#title' => '<span class="element-invisible">' . $title . '</span>',
-        '#default_value' => !empty($this->configuration['visibility']['path']['pages']) ? $this->configuration['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($this->configuration['visibility']['language']['language_type']) ? $this->configuration['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($this->configuration['visibility']['language']['langcodes']) ? $this->configuration['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_roles());
-    $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($this->configuration['visibility']['role']['roles']) ? $this->configuration['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 specific configuration for this block type.
-    $form += $this->blockForm($form, $form_state);
-
-    $form['actions'] = array('#type' => 'actions');
-    $form['actions']['submit'] = array(
-      '#type' => 'submit',
-      '#value' => t('Save block'),
-    );
-
-    return $form;
-  }
-
-  /**
    * Returns the configuration form elements specific to this block plugin.
    *
    * Blocks that need to add form elements to the normal block configuration
@@ -445,44 +154,6 @@ public function blockForm($form, &$form_state) {
   }
 
   /**
-   * Implements \Drupal\block\BlockInterface::validate().
-   *
-   * Most block plugins should not override this method. To add validation
-   * for a specific block type, override BlockBase::blockValdiate().
-   *
-   * @todo Add inline documentation to this method.
-   *
-   * @see \Drupal\block\BlockBase::blockValidate()
-   */
-  public function validate($form, &$form_state) {
-    if (empty($form['settings']['machine_name']['#disabled'])) {
-      if (preg_match('/[^a-zA-Z0-9_]/', $form_state['values']['machine_name'])) {
-        form_set_error('machine_name', t('Block name must be alphanumeric or underscores only.'));
-      }
-      if (in_array('plugin.core.block.' . $form_state['values']['machine_name'], config_get_storage_names_with_prefix('plugin.core.block'))) {
-        form_set_error('machine_name', t('Block name must be unique.'));
-      }
-    }
-    else {
-      $config_id = explode('.', $form_state['values']['machine_name']);
-      $form_state['values']['machine_name'] = array_pop($config_id);
-    }
-    if ($form_state['values']['module'] == 'block') {
-      $custom_block_exists = (bool) db_query_range('SELECT 1 FROM {block_custom} WHERE bid <> :bid AND info = :info', 0, 1, array(
-        ':bid' => $form_state['values']['delta'],
-        ':info' => $form_state['values']['info'],
-      ))->fetchField();
-      if (empty($form_state['values']['info']) || $custom_block_exists) {
-        form_set_error('info', t('Ensure that each block description is unique.'));
-      }
-    }
-    $form_state['values']['visibility']['role']['roles'] = array_filter($form_state['values']['visibility']['role']['roles']);
-
-    // Perform block type-specific validation.
-    $this->blockValidate($form, $form_state);
-  }
-
-  /**
    * Adds block type-specific validation for the block form.
    *
    * Note that this method takes the form structure and form state arrays for
@@ -501,47 +172,6 @@ public function validate($form, &$form_state) {
   public function blockValidate($form, &$form_state) {}
 
   /**
-   * Implements \Drupal\block\BlockInterface::submit().
-   *
-   * Most block plugins should not override this method. To add submission
-   * handling for a specific block type, override BlockBase::blockSubmit().
-   *
-   * @todo Add inline documentation to this method.
-   *
-   * @see \Drupal\block\BlockBase::blockSubmit()
-   */
-  public function submit($form, &$form_state) {
-    if (!form_get_errors()) {
-      $transaction = db_transaction();
-      try {
-        $keys = array(
-          'visibility' => 'visibility',
-          'pages' => 'pages',
-          'title' => 'subject',
-          'module' => 'module',
-          'region' => 'region',
-        );
-        foreach ($keys as $key => $new_key) {
-          if (isset($form_state['values'][$key])) {
-            $this->configuration[$new_key] = $form_state['values'][$key];
-          }
-        }
-      }
-      catch (Exception $e) {
-        $transaction->rollback();
-        watchdog_exception('block', $e);
-        throw $e;
-      }
-      if (empty($this->configuration['weight'])) {
-        $this->configuration['weight'] = 0;
-      }
-
-      // Perform block type-specific validation.
-      $this->blockSubmit($form, $form_state);
-    }
-  }
-
-  /**
    * Adds block type-specific submission handling for the block form.
    *
    * Note that this method takes the form structure and form state arrays for
@@ -582,9 +212,7 @@ public function build() {
     // hook_block_view_NAME_alter().
     $id = str_replace(':', '__', $this->getPluginId());
 
-    $config = $this->getConfig();
-    $config_id = explode('.', $config['config_id']);
-    $name = array_pop($config_id);
+    $name = '';
 
     $build = $this->blockBuild();
     drupal_alter(array('block_view', "block_view_$id", "block_view_$name"), $build, $this);
diff --git a/core/modules/block/lib/Drupal/block/BlockFormController.php b/core/modules/block/lib/Drupal/block/BlockFormController.php
new file mode 100644
index 0000000..51c483e
--- /dev/null
+++ b/core/modules/block/lib/Drupal/block/BlockFormController.php
@@ -0,0 +1,272 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\block\BlockFormController.
+ */
+
+namespace Drupal\block;
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityFormController;
+
+/**
+ * Form controller for the user account forms.
+ */
+class BlockFormController extends EntityFormController {
+
+  /**
+   * Overrides \Drupal\Core\Entity\EntityFormController::form().
+   */
+  public function form(array $form, array &$form_state, EntityInterface $entity) {
+    $definition = $entity->getDefinition();
+    $form['module'] = array(
+      '#type' => 'value',
+      '#value' => $definition['module'],
+    );
+    $form['id'] = array(
+      '#type' => 'value',
+      '#value' => $entity->id(),
+    );
+
+    // Get the theme for the page title.
+    $admin_theme = config('system.theme')->get('admin');
+    $themes = list_themes();
+    $theme_key = $entity->get('theme');
+    $theme = $themes[$theme_key];
+    // Use meaningful titles for the main site and administrative themes.
+    $theme_title = $theme->info['name'];
+    if ($theme_key == variable_get('theme_default', 'stark')) {
+      $theme_title = t('!theme (default theme)', array('!theme' => $theme_title));
+    }
+    elseif ($admin_theme && $theme_key == $admin_theme) {
+      $theme_title = t('!theme (administration theme)', array('!theme' => $theme_title));
+    }
+
+    // Get the block subject for the page title.
+    if ($label = $entity->label()) {
+      drupal_set_title(t("%label block in %theme", array('%label' => $label, '%theme' => $theme_title)), PASS_THROUGH);
+    }
+
+    $form['settings'] = array(
+      '#weight' => -5,
+    );
+    $form['settings']['title'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Block title'),
+      '#maxlength' => 255,
+      '#default_value' => $label,
+    );
+    $form['settings']['machine_name'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Block 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(),
+      '#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($theme_key, REGIONS_VISIBLE),
+    );
+
+    // Visibility settings.
+    $form['visibility_title'] = array(
+      '#type' => 'item',
+      '#title' => t('Visibility settings'),
+      '#weight' => 10,
+    );
+    $form['visibility'] = array(
+      '#type' => 'vertical_tabs',
+      '#attached' => array(
+        'js' => array(drupal_get_path('module', 'block') . '/block.js'),
+      ),
+      '#tree' => TRUE,
+      '#weight' => 15,
+    );
+
+    // 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_roles());
+    $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 specific configuration for this block type.
+    $form += $entity->getPlugin()->blockForm($form, $form_state);
+
+    return parent::form($form, $form_state, $entity);
+  }
+
+  /**
+   * Overrides \Drupal\Core\Entity\EntityFormController::actions().
+   */
+  protected function actions(array $form, array &$form_state) {
+    $actions = parent::actions($form, $form_state);
+    $actions['submit']['#value'] = t('Save block');
+    return $actions;
+  }
+
+  /**
+   * Overrides \Drupal\Core\Entity\EntityFormController::validate().
+   */
+  public function validate(array $form, array &$form_state) {
+    parent::validate($form, $form_state);
+
+    if (empty($form['settings']['machine_name']['#disabled'])) {
+      if (preg_match('/[^a-zA-Z0-9_]/', $form_state['values']['machine_name'])) {
+        form_set_error('machine_name', t('Block name must be alphanumeric or underscores only.'));
+      }
+      if (in_array('plugin.core.block.' . $form_state['values']['machine_name'], config_get_storage_names_with_prefix('plugin.core.block'))) {
+        form_set_error('machine_name', t('Block name must be unique.'));
+      }
+    }
+    else {
+      $config_id = explode('.', $form_state['values']['machine_name']);
+      $form_state['values']['machine_name'] = array_pop($config_id);
+    }
+    if ($form_state['values']['module'] == 'block') {
+      $custom_block_exists = (bool) db_query_range('SELECT 1 FROM {block_custom} WHERE bid <> :bid AND info = :info', 0, 1, array(
+        ':bid' => $form_state['values']['delta'],
+        ':info' => $form_state['values']['info'],
+      ))->fetchField();
+      if (empty($form_state['values']['info']) || $custom_block_exists) {
+        form_set_error('info', t('Ensure that each block description is unique.'));
+      }
+    }
+    $form_state['values']['visibility']['role']['roles'] = array_filter($form_state['values']['visibility']['role']['roles']);
+    $entity = $this->getEntity($form_state);
+    if ($entity->isNew()) {
+      form_set_value($form['id'], $entity->get('theme') . '.' . $form_state['values']['machine_name'], $form_state);
+    }
+    $entity->getPlugin()->blockValidate($form, $form_state);
+  }
+
+  /**
+   * Overrides \Drupal\Core\Entity\EntityFormController::submit().
+   */
+  public function submit(array $form, array &$form_state) {
+    parent::submit($form, $form_state);
+
+    $entity = $this->getEntity($form_state);
+    $entity->getPlugin()->blockSubmit($form, $form_state);
+    $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/BlockInterface.php b/core/modules/block/lib/Drupal/block/BlockInterface.php
index b419b27..164996b 100644
--- a/core/modules/block/lib/Drupal/block/BlockInterface.php
+++ b/core/modules/block/lib/Drupal/block/BlockInterface.php
@@ -31,62 +31,6 @@
   public function settings();
 
   /**
-   * Indicates whether the block should be shown.
-   *
-   * This method allows base implementations to add general access restrictions
-   * that should apply to all extending block plugins.
-   *
-   * @return bool
-   *   TRUE if the block should be shown, or FALSE otherwise.
-   */
-  public function access();
-
-  /**
-   * Constructs the block configuration form.
-   *
-   * This method allows base implementations to add a generic configuration
-   * form for extending block plugins.
-   *
-   * @param array $form
-   *   The form definition array for the block configuration form.
-   * @param array $form_state
-   *   An array containing the current state of the configuration form.
-   *
-   * @return array $form
-   *   The renderable form array representing the entire configuration form.
-   *
-   * @see \Drupal\block\BlockInterace::validate()
-   * @see \Drupal\block\BlockInterace::submit()
-   */
-  public function form($form, &$form_state);
-
-  /**
-   * Handles form validation for the block configuration form.
-   *
-   * @param array $form
-   *   The form definition array for the block configuration form.
-   * @param array $form_state
-   *   An array containing the current state of the configuration form.
-   *
-   * @see \Drupal\block\BlockInterace::form()
-   * @see \Drupal\block\BlockInterace::submit()
-   */
-  public function validate($form, &$form_state);
-
-  /**
-   * Handles form submissions for the block configuration form.
-   *
-   * @param array $form
-   *   The form definition array for the block configuration form.
-   * @param array $form_state
-   *   An array containing the current state of the configuration form.
-   *
-   * @see \Drupal\block\BlockInterace::form()
-   * @see \Drupal\block\BlockInterace::validate()
-   */
-  public function submit($form, &$form_state);
-
-  /**
    * Builds and returns the renderable array for this block.
    *
    * @return array
diff --git a/core/modules/block/lib/Drupal/block/BlockStorageController.php b/core/modules/block/lib/Drupal/block/BlockStorageController.php
new file mode 100644
index 0000000..eba8c33
--- /dev/null
+++ b/core/modules/block/lib/Drupal/block/BlockStorageController.php
@@ -0,0 +1,17 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\block\BlockStorageController.
+ */
+
+namespace Drupal\block;
+
+use Drupal\Core\Config\Entity\ConfigStorageController;
+
+/**
+ * Defines the storage controller class for Block entities.
+ */
+class BlockStorageController extends ConfigStorageController {
+
+}
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
new file mode 100644
index 0000000..c00f5cb
--- /dev/null
+++ b/core/modules/block/lib/Drupal/block/Plugin/Core/Entity/Block.php
@@ -0,0 +1,245 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\block\Plugin\Core\Entity\Block.
+ */
+
+namespace Drupal\block\Plugin\Core\Entity;
+
+use Drupal\user\Plugin\Core\Entity\User;
+use Drupal\Core\Config\Entity\ConfigEntityBase;
+use Drupal\Core\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
+
+/**
+ * Defines a Block configuration entity class.
+ *
+ * @Plugin(
+ *   id = "block",
+ *   label = @Translation("Block"),
+ *   module = "block",
+ *   controller_class = "Drupal\block\BlockStorageController",
+ *   form_controller_class = {
+ *     "default" = "Drupal\block\BlockFormController"
+ *   },
+ *   config_prefix = "block.block",
+ *   fieldable = FALSE,
+ *   entity_keys = {
+ *     "id" = "id",
+ *     "label" = "label",
+ *     "uuid" = "uuid"
+ *   }
+ * )
+ */
+class Block extends ConfigEntityBase {
+
+  /**
+   * The id of the block.
+   *
+   * @var string
+   */
+  public $id;
+
+  /**
+   * The block label.
+   *
+   * @var string
+   */
+  public $label;
+
+  /**
+   * The block UUID.
+   *
+   * @var string
+   */
+  public $uuid;
+
+  /**
+   * @todo.
+   *
+   * @var array
+   */
+  protected $configuration = array();
+
+  /**
+   * @todo.
+   *
+   * @var \Drupal\block\BlockInterface
+   */
+  protected $plugin;
+
+  protected $region;
+
+  protected $weight;
+
+  protected $cache;
+
+  protected $theme;
+
+  protected $module;
+
+  protected $status = TRUE;
+
+  protected $pluginID;
+
+  /**
+   * @todo.
+   */
+  public function __construct(array $values, $entity_type) {
+    parent::__construct($values, $entity_type);
+
+    $this->plugin = drupal_container()->get('plugin.manager.block')->createInstance($values['pluginID']);
+    $this->plugin->init($this);
+    if (!isset($this->theme) && $id = $this->id()) {
+      list($this->theme) = explode('.', $id);
+    }
+  }
+
+  /**
+   * @todo.
+   *
+   * @return array
+   */
+  public function getDefinition() {
+    return $this->plugin->getDefinition() + $this->plugin->getConfig() + $this->getExportProperties();
+  }
+
+  /**
+   * @todo.
+   *
+   * @var \Drupal\block\BlockInterface
+   */
+  public function getPlugin() {
+    return $this->plugin;
+  }
+
+  /**
+   * @todo.
+   *
+   * @var string
+   */
+  public function getPluginId() {
+    return $this->plugin->getPluginId();
+  }
+
+  /**
+   * Overrides \Drupal\Core\Config\Entity\ConfigEntityBase::getExportProperties();
+   */
+  public function getExportProperties() {
+    $names = array(
+      'id',
+      'label',
+      'uuid',
+      'region',
+      'weight',
+      'cache',
+      'module',
+      'theme',
+      'status',
+      'visibility',
+      'pluginID',
+    );
+    $properties = array();
+    foreach ($names as $name) {
+      $properties[$name] = $this->get($name);
+    }
+    return $properties;
+  }
+
+  /**
+   * 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.
+   *
+   * @see hook_block_access()
+   * @see \Drupal\block\BlockBase::blockAccess()
+   */
+  public function access($operation = 'view', User $account = NULL) {
+    // If the block-specific access restrictions indicate the block is not
+    // accessible, always deny access.
+    if (!$this->getPlugin()->blockAccess()) {
+      return FALSE;
+    }
+
+    // Otherwise, check for other access restrictions.
+    if (!$account) {
+      global $user;
+      $account = $user;
+    }
+
+    // Deny access to disabled blocks.
+    if (!$this->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->get('visibility');
+    if (!empty($visibility['role']['roles']) && !array_intersect(array_filter($visibility['role']['roles']), array_keys($account->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) === FALSE) {
+        return FALSE;
+      }
+    }
+
+    // If nothing denied access to the block, it is accessible.
+    return TRUE;
+  }
+
+}
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 7cbba86..5db1850 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -1986,14 +1986,13 @@ function theme_node_recent_content($variables) {
 }
 
 /**
- * Implements hook_form_FORM_ID_alter() for block_admin_configure().
+ * Implements hook_form_FORM_ID_alter() for block_form().
  *
  * Adds node-type specific visibility options to block configuration form.
- *
- * @see node_form_block_admin_configure_submit()
  */
-function node_form_block_admin_configure_alter(&$form, &$form_state) {
-  $config = $form['#instance']->getConfig();
+function node_form_block_form_alter(&$form, &$form_state) {
+  $block = $form_state['entity'];
+  $visibility = $block->get('visibility');
   $form['visibility']['node_type'] = array(
     '#type' => 'details',
     '#title' => t('Content types'),
@@ -2005,7 +2004,7 @@ function node_form_block_admin_configure_alter(&$form, &$form_state) {
   $form['visibility']['node_type']['types'] = array(
     '#type' => 'checkboxes',
     '#title' => t('Show block for specific content types'),
-    '#default_value' => !empty($config['visibility']['node_type']['types']) ? $config['visibility']['node_type']['types'] : array(),
+    '#default_value' => !empty($visibility['node_type']['types']) ? $visibility['node_type']['types'] : array(),
     '#options' => node_type_get_names(),
     '#description' => t('Show this block only on pages that display content of the given type(s). If you select no types, there will be no type-specific limitation.'),
   );
@@ -2035,9 +2034,8 @@ function node_modules_uninstalled($modules) {
  * if the visibility conditions are not met.
  */
 function node_block_access($block) {
-  $configuration = $block->getConfig();
-  if (!empty($configuration['visibility'])) {
-    $visibility = $configuration['visibility'];
+  $visibility = $block->get('visibility');
+  if (!empty($visibility)) {
     $allowed_types = array();
     $node = menu_get_object();
     $node_types = node_type_get_types();
diff --git a/core/profiles/standard/config/plugin.core.block.bartik.content.yml b/core/profiles/standard/config/block.block.bartik.content.yml
similarity index 71%
rename from core/profiles/standard/config/plugin.core.block.bartik.content.yml
rename to core/profiles/standard/config/block.block.bartik.content.yml
index e10f903..819e145 100644
--- a/core/profiles/standard/config/plugin.core.block.bartik.content.yml
+++ b/core/profiles/standard/config/block.block.bartik.content.yml
@@ -1,4 +1,6 @@
-id: system_main_block
+id: bartik.content
+label: ''
+pluginID: system_main_block
 status: '1'
 cache: '-1'
 visibility:
@@ -12,7 +14,8 @@ visibility:
       article: '0'
       page: '0'
   visibility__active_tab: edit-visibility-path
-subject: ''
+label: ''
 module: system
 region: content
-weight: '0'
+weight: '-3'
+langcode: und
diff --git a/core/profiles/standard/config/plugin.core.block.bartik.footer.yml b/core/profiles/standard/config/block.block.bartik.footer.yml
similarity index 68%
rename from core/profiles/standard/config/plugin.core.block.bartik.footer.yml
rename to core/profiles/standard/config/block.block.bartik.footer.yml
index 7b6f9b7..1002bd7 100644
--- a/core/profiles/standard/config/plugin.core.block.bartik.footer.yml
+++ b/core/profiles/standard/config/block.block.bartik.footer.yml
@@ -1,7 +1,9 @@
-id: 'system_menu_block:menu-footer'
+id: bartik.footer
+label: 'Footer menu'
+pluginID: 'system_menu_block:menu-footer'
 status: '1'
 cache: '-1'
-subject: 'Footer menu'
+label: 'Footer menu'
 visibility:
   path:
     visibility: '0'
@@ -16,3 +18,4 @@ visibility:
 module: system
 region: footer
 weight: '0'
+langcode: und
diff --git a/core/profiles/standard/config/plugin.core.block.seven.help.yml b/core/profiles/standard/config/block.block.bartik.help.yml
similarity index 76%
rename from core/profiles/standard/config/plugin.core.block.seven.help.yml
rename to core/profiles/standard/config/block.block.bartik.help.yml
index a5c4467..b2751fd 100644
--- a/core/profiles/standard/config/plugin.core.block.seven.help.yml
+++ b/core/profiles/standard/config/block.block.bartik.help.yml
@@ -1,4 +1,6 @@
-id: system_help_block
+id: bartik.help
+label: ''
+pluginID: system_help_block
 status: '1'
 cache: '-1'
 visibility:
@@ -12,7 +14,8 @@ visibility:
       article: '0'
       page: '0'
   visibility__active_tab: edit-visibility-path
-subject: ''
+label: ''
 module: system
 region: help
 weight: '0'
+langcode: und
diff --git a/core/profiles/standard/config/plugin.core.block.bartik.search.yml b/core/profiles/standard/config/block.block.bartik.login.yml
similarity index 72%
copy from core/profiles/standard/config/plugin.core.block.bartik.search.yml
copy to core/profiles/standard/config/block.block.bartik.login.yml
index 466659b..ce50aae 100644
--- a/core/profiles/standard/config/plugin.core.block.bartik.search.yml
+++ b/core/profiles/standard/config/block.block.bartik.login.yml
@@ -1,4 +1,5 @@
-id: search_form_block
+id: bartik.login
+label: 'User login'
 status: '1'
 cache: '-1'
 visibility:
@@ -12,7 +13,8 @@ visibility:
       article: '0'
       page: '0'
   visibility__active_tab: edit-visibility-path
-subject: 'Search'
-module: search
+module: user
 region: sidebar_first
 weight: '0'
+pluginID: user_login_block
+langcode: und
diff --git a/core/profiles/testing/config/plugin.core.block.stark.tools.yml b/core/profiles/standard/config/block.block.bartik.navigation.yml
similarity index 67%
rename from core/profiles/testing/config/plugin.core.block.stark.tools.yml
rename to core/profiles/standard/config/block.block.bartik.navigation.yml
index 5e8b188..57255fc 100644
--- a/core/profiles/testing/config/plugin.core.block.stark.tools.yml
+++ b/core/profiles/standard/config/block.block.bartik.navigation.yml
@@ -1,4 +1,6 @@
-id: 'system_menu_block:menu-tools'
+id: bartik.navigation
+label: 'Main navigation'
+pluginID: 'system_menu_block:menu-main'
 status: '1'
 cache: '-1'
 visibility:
@@ -12,7 +14,8 @@ visibility:
       article: '0'
       page: '0'
   visibility__active_tab: edit-visibility-path
-subject: ''
+label: 'Main navigation'
 module: system
 region: sidebar_first
 weight: '0'
+langcode: und
diff --git a/core/profiles/standard/config/plugin.core.block.bartik.powered.yml b/core/profiles/standard/config/block.block.bartik.powered.yml
similarity index 74%
rename from core/profiles/standard/config/plugin.core.block.bartik.powered.yml
rename to core/profiles/standard/config/block.block.bartik.powered.yml
index 3ef20d7..bce83ce 100644
--- a/core/profiles/standard/config/plugin.core.block.bartik.powered.yml
+++ b/core/profiles/standard/config/block.block.bartik.powered.yml
@@ -1,4 +1,6 @@
-id: system_powered_by_block
+id: bartik.powered
+label: ''
+pluginID: system_powered_by_block
 status: '1'
 cache: '-1'
 visibility:
@@ -12,7 +14,8 @@ visibility:
       article: '0'
       page: '0'
   visibility__active_tab: edit-visibility-path
-subject: ''
+label: ''
 module: system
 region: footer
 weight: '0'
+langcode: und
diff --git a/core/profiles/standard/config/plugin.core.block.bartik.search.yml b/core/profiles/standard/config/block.block.bartik.search.yml
similarity index 68%
rename from core/profiles/standard/config/plugin.core.block.bartik.search.yml
rename to core/profiles/standard/config/block.block.bartik.search.yml
index 466659b..5aac33b 100644
--- a/core/profiles/standard/config/plugin.core.block.bartik.search.yml
+++ b/core/profiles/standard/config/block.block.bartik.search.yml
@@ -1,4 +1,6 @@
-id: search_form_block
+id: bartik.search
+label: 'Search'
+pluginID: search_form_block
 status: '1'
 cache: '-1'
 visibility:
@@ -12,7 +14,9 @@ visibility:
       article: '0'
       page: '0'
   visibility__active_tab: edit-visibility-path
-subject: 'Search'
+  region: sidebar_first
+label: 'Search'
 module: search
 region: sidebar_first
 weight: '0'
+langcode: und
diff --git a/core/profiles/testing/config/plugin.core.block.stark.admin.yml b/core/profiles/standard/config/block.block.bartik.tools.yml
similarity index 71%
rename from core/profiles/testing/config/plugin.core.block.stark.admin.yml
rename to core/profiles/standard/config/block.block.bartik.tools.yml
index 960e2cb..bf918ff 100644
--- a/core/profiles/testing/config/plugin.core.block.stark.admin.yml
+++ b/core/profiles/standard/config/block.block.bartik.tools.yml
@@ -1,4 +1,6 @@
-id: 'system_menu_block:menu-admin'
+id: bartik.tools
+label: 'Tools'
+pluginID: 'system_menu_block:menu-tools'
 status: '1'
 cache: '-1'
 visibility:
@@ -12,7 +14,8 @@ visibility:
       article: '0'
       page: '0'
   visibility__active_tab: edit-visibility-path
-subject: ''
+label: 'Tools'
 module: system
 region: sidebar_first
 weight: '0'
+langcode: und
diff --git a/core/profiles/standard/config/plugin.core.block.seven.content.yml b/core/profiles/standard/config/block.block.seven.content.yml
similarity index 75%
rename from core/profiles/standard/config/plugin.core.block.seven.content.yml
rename to core/profiles/standard/config/block.block.seven.content.yml
index 51b155f..a87bfed 100644
--- a/core/profiles/standard/config/plugin.core.block.seven.content.yml
+++ b/core/profiles/standard/config/block.block.seven.content.yml
@@ -1,4 +1,6 @@
-id: system_main_block
+id: seven.content
+label: ''
+pluginID: system_main_block
 status: '1'
 cache: '-1'
 visibility:
@@ -12,7 +14,8 @@ visibility:
       article: '0'
       page: '0'
   visibility__active_tab: edit-visibility-path
-subject: ''
+label: ''
 module: system
 region: content
 weight: '-3'
+langcode: und
diff --git a/core/profiles/standard/config/plugin.core.block.bartik.help.yml b/core/profiles/standard/config/block.block.seven.help.yml
similarity index 75%
rename from core/profiles/standard/config/plugin.core.block.bartik.help.yml
rename to core/profiles/standard/config/block.block.seven.help.yml
index a5c4467..cda1a92 100644
--- a/core/profiles/standard/config/plugin.core.block.bartik.help.yml
+++ b/core/profiles/standard/config/block.block.seven.help.yml
@@ -1,4 +1,6 @@
-id: system_help_block
+id: bartik.content
+label: ''
+pluginID: system_help_block
 status: '1'
 cache: '-1'
 visibility:
@@ -12,7 +14,8 @@ visibility:
       article: '0'
       page: '0'
   visibility__active_tab: edit-visibility-path
-subject: ''
+label: ''
 module: system
 region: help
 weight: '0'
+langcode: und
diff --git a/core/profiles/standard/config/plugin.core.block.bartik.login.yml b/core/profiles/standard/config/block.block.seven.login.yml
similarity index 76%
rename from core/profiles/standard/config/plugin.core.block.bartik.login.yml
rename to core/profiles/standard/config/block.block.seven.login.yml
index 8d8923a..1bf01e7 100644
--- a/core/profiles/standard/config/plugin.core.block.bartik.login.yml
+++ b/core/profiles/standard/config/block.block.seven.login.yml
@@ -1,5 +1,5 @@
-id: user_login_block
-whois_new_count: '5'
+id: seven.login
+label: 'User login'
 status: '1'
 cache: '-1'
 visibility:
@@ -13,7 +13,8 @@ visibility:
       article: '0'
       page: '0'
   visibility__active_tab: edit-visibility-path
-subject: 'User login'
 module: user
 region: sidebar_first
 weight: '0'
+pluginID: user_login_block
+langcode: und
diff --git a/core/profiles/standard/config/plugin.core.block.seven.navigation.yml b/core/profiles/standard/config/block.block.seven.navigation.yml
similarity index 66%
rename from core/profiles/standard/config/plugin.core.block.seven.navigation.yml
rename to core/profiles/standard/config/block.block.seven.navigation.yml
index 7fc3e2c..d5b0eee 100644
--- a/core/profiles/standard/config/plugin.core.block.seven.navigation.yml
+++ b/core/profiles/standard/config/block.block.seven.navigation.yml
@@ -1,5 +1,7 @@
+id: bartik.content
+label: 'Main navigation'
 region: '-1'
-id: 'system_menu_block:menu-main'
+pluginID: 'system_menu_block:menu-main'
 status: '1'
 cache: '-1'
 visibility:
@@ -13,6 +15,7 @@ visibility:
       article: '0'
       page: '0'
   visibility__active_tab: edit-visibility-path
-subject: 'Main navigation'
+label: 'Main navigation'
 module: system
 weight: '-2'
+langcode: und
diff --git a/core/profiles/standard/config/plugin.core.block.seven.powered.yml b/core/profiles/standard/config/block.block.seven.powered.yml
similarity index 74%
rename from core/profiles/standard/config/plugin.core.block.seven.powered.yml
rename to core/profiles/standard/config/block.block.seven.powered.yml
index b9aac19..70e19ea 100644
--- a/core/profiles/standard/config/plugin.core.block.seven.powered.yml
+++ b/core/profiles/standard/config/block.block.seven.powered.yml
@@ -1,5 +1,7 @@
+id: bartik.content
+label: ''
 region: '-1'
-id: system_powered_by_block
+pluginID: system_powered_by_block
 status: '1'
 cache: '-1'
 visibility:
@@ -13,6 +15,7 @@ visibility:
       article: '0'
       page: '0'
   visibility__active_tab: edit-visibility-path
-subject: ''
+label: ''
 module: system
 weight: '0'
+langcode: und
diff --git a/core/profiles/standard/config/plugin.core.block.seven.search.yml b/core/profiles/standard/config/block.block.seven.search.yml
similarity index 72%
rename from core/profiles/standard/config/plugin.core.block.seven.search.yml
rename to core/profiles/standard/config/block.block.seven.search.yml
index 081dfca..740e68d 100644
--- a/core/profiles/standard/config/plugin.core.block.seven.search.yml
+++ b/core/profiles/standard/config/block.block.seven.search.yml
@@ -1,5 +1,7 @@
+id: bartik.content
+label: 'Search'
 region: '-1'
-id: search_form_block
+pluginID: search_form_block
 status: '1'
 cache: '-1'
 visibility:
@@ -13,6 +15,7 @@ visibility:
       article: '0'
       page: '0'
   visibility__active_tab: edit-visibility-path
-subject: 'Search'
+label: 'Search'
 module: search
 weight: '-1'
+langcode: und
diff --git a/core/profiles/standard/config/plugin.core.block.seven.login.yml b/core/profiles/standard/config/plugin.core.block.seven.login.yml
deleted file mode 100644
index 8352fab..0000000
--- a/core/profiles/standard/config/plugin.core.block.seven.login.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-region: '-1'
-id: user_login_block
-whois_new_count: '5'
-status: '1'
-cache: '-1'
-visibility:
-  path:
-    visibility: '0'
-    pages: ''
-  role:
-    roles: {  }
-  node_type:
-    types:
-      article: '0'
-      page: '0'
-  visibility__active_tab: edit-visibility-path
-subject: 'User login'
-module: user
-weight: '-3'
diff --git a/core/profiles/standard/config/plugin.core.block.bartik.navigation.yml b/core/profiles/testing/config/block.block.stark.admin.yml
similarity index 73%
rename from core/profiles/standard/config/plugin.core.block.bartik.navigation.yml
rename to core/profiles/testing/config/block.block.stark.admin.yml
index f16c6f4..094adf7 100644
--- a/core/profiles/standard/config/plugin.core.block.bartik.navigation.yml
+++ b/core/profiles/testing/config/block.block.stark.admin.yml
@@ -1,4 +1,6 @@
-id: 'system_menu_block:menu-main'
+id: stark.admin
+label: ''
+pluginID: 'system_menu_block:menu-admin'
 status: '1'
 cache: '-1'
 visibility:
@@ -12,7 +14,8 @@ visibility:
       article: '0'
       page: '0'
   visibility__active_tab: edit-visibility-path
-subject: 'Main navigation'
+label: ''
 module: system
 region: sidebar_first
 weight: '0'
+langcode: und
diff --git a/core/profiles/testing/config/plugin.core.block.stark.online.yml b/core/profiles/testing/config/block.block.stark.online.yml
similarity index 76%
rename from core/profiles/testing/config/plugin.core.block.stark.online.yml
rename to core/profiles/testing/config/block.block.stark.online.yml
index 3b3f5c5..b8534f5 100644
--- a/core/profiles/testing/config/plugin.core.block.stark.online.yml
+++ b/core/profiles/testing/config/block.block.stark.online.yml
@@ -1,11 +1,13 @@
-id: user_online_block
+id: stark.online
+label: 'Who''s online'
+pluginID: user_online_block
 properties:
   administrative: '1'
 seconds_online: '900'
 max_list_count: '10'
 status: '1'
 cache: '-1'
-subject: 'Who''s online'
+label: 'Who''s online'
 visibility:
   path:
     visibility: '0'
@@ -21,3 +23,4 @@ visibility:
 module: user
 region: sidebar_first
 weight: '0'
+langcode: und
diff --git a/core/profiles/standard/config/plugin.core.block.bartik.tools.yml b/core/profiles/testing/config/block.block.stark.tools.yml
similarity index 73%
rename from core/profiles/standard/config/plugin.core.block.bartik.tools.yml
rename to core/profiles/testing/config/block.block.stark.tools.yml
index d6a38c9..a9ced99 100644
--- a/core/profiles/standard/config/plugin.core.block.bartik.tools.yml
+++ b/core/profiles/testing/config/block.block.stark.tools.yml
@@ -1,4 +1,6 @@
-id: 'system_menu_block:menu-tools'
+id: stark.tools
+label: ''
+pluginID: 'system_menu_block:menu-tools'
 status: '1'
 cache: '-1'
 visibility:
@@ -12,7 +14,8 @@ visibility:
       article: '0'
       page: '0'
   visibility__active_tab: edit-visibility-path
-subject: 'Tools'
+label: ''
 module: system
 region: sidebar_first
 weight: '0'
+langcode: und
