diff --git a/fieldblock.install b/fieldblock.install
index f1da813453eccdc9a6940617447548ff91b647d3..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644
--- a/fieldblock.install
+++ b/fieldblock.install
@@ -1,86 +0,0 @@
-<?php
-
-///**
-// * Implements hook_uninstall().
-// */
-//function fieldblock_uninstall() {
-//  // Delete variables.
-//  $entities = entity_get_info();
-//  // Loop over the entity types.
-//  foreach ($entities as $entity_type => $entity_info) {
-//    // Loop over each entity type's bundles.
-//    foreach ($entity_info['bundles'] as $bundle => $bundle_info) {
-//      $view_modes = field_view_mode_settings($entity_type, $bundle);
-//      // Treat the default settings as a real view mode with custom settings.
-//      $view_modes['default']['custom_settings'] = true;
-//      // Loop over the bundle's view modes.
-//      foreach ($view_modes as $view_mode => $view_mode_info) {
-//        // Delete the variable, if it exists.
-//        $variable_name = 'fieldblock-'. $entity_type .'-'. $bundle .'-'. $view_mode;
-//        variable_del($variable_name);
-//      }
-//    }
-//  }
-//}
-//
-///**
-// * Legacy helper function to undo drupal core schema alter.
-// */
-//function _fieldblock_db_alter_block_delta_length($length) {
-//  // Alter block table.
-//  db_drop_unique_key('block', 'tmd');
-//  db_change_field('block', 'delta', 'delta',
-//    array(
-//      'type' => 'varchar',
-//      'length' => $length,
-//      'not null' => TRUE,
-//      'default' => '0',
-//      'description' => 'Unique ID for block within a module.',
-//    ),
-//    array(
-//      'unique keys' => array(
-//        'tmd' => array('theme', 'module', 'delta'),
-//      )
-//    )
-//  );
-//
-//  // Alter block_role table.
-//  db_drop_primary_key('block_role');
-//  db_change_field('block_role', 'delta', 'delta',
-//    array(
-//      'type' => 'varchar',
-//      'length' => $length,
-//      'not null' => TRUE,
-//      'description' => "The block's unique delta within module, from {block}.delta.",
-//    ),
-//    array(
-//      'primary key' => array('module', 'delta', 'rid'),
-//    )
-//  );
-//
-//  // Alter block_node_type table.
-//  db_drop_primary_key('block_node_type');
-//  db_change_field('block_node_type', 'delta', 'delta',
-//    array(
-//      'type' => 'varchar',
-//      'length' => $length,
-//      'not null' => TRUE,
-//      'description' => "The block's unique delta within module, from {block}.delta.",
-//    ),
-//    array(
-//      'primary key' => array('module', 'delta', 'type'),
-//    )
-//  );
-//}
-//
-///**
-// * Update legacy fieldblock deltas to use md5 identifier.
-// * Reset drupal core block schema.
-// */
-//function fieldblock_update_7100() {
-//  $blocks = db_query("SELECT bid, delta FROM {block} WHERE module = 'fieldblock'");
-//  foreach ($blocks as $block) {
-//    db_query("UPDATE {block} SET delta = :new_delta WHERE bid = :bid AND delta = :old_delta AND module = 'fieldblock'", array(':new_delta' => md5($block->delta), ':bid' => $block->bid, ':old_delta' => $block->delta));
-//  }
-//  _fieldblock_db_alter_block_delta_length(32);
-//}
diff --git a/fieldblock.module b/fieldblock.module
index 01a63b10541a35dcc593e60727130fdcbf5c9d21..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644
--- a/fieldblock.module
+++ b/fieldblock.module
@@ -1,113 +0,0 @@
-<?php
-
-/**
- * @file
- * Allow fields to be rendered in blocks.
- */
-
-use Drupal\Core\Form\FormStateInterface;
-use Drupal\Core\Entity\Entity\EntityViewDisplay;
-use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
-
-/**
- * Implements hook_form_alter().
- *
- * Adds a column to the "display fields" table-form, with a checkbox for each
- * field.
- */
-function fieldblock_form_field_ui_display_overview_form_alter(&$form, FormStateInterface &$form_state, $form_id) {
-  $entity_type = $form['#entity_type'];
-  $bundle = $form['#bundle'];
-  $mode = $form['#mode'];
-
-  /** @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface $entity_view_display */
-  $entity_view_display = EntityViewDisplay::load($entity_type . '.' . $bundle . '.' . $mode);
-
-  // Add a column header.
-  $form['fields']['#header'][] = t('Display as block');
-
-  // Add checkboxes.
-  $field_names = array_merge($form['#fields'], $form['#extra']);
-  foreach ($field_names as $field_name) {
-    $form['fields'][$field_name]['fieldblock'] = array(
-      '#type' => 'checkbox',
-      '#default_value' => $entity_view_display->getThirdPartySetting('fieldblock', $field_name) ? true : false,
-      '#title' => '',
-    );
-  }
-
-  // Add a submit handler.
-  $form['#submit'][] = 'fieldblock_field_display_submit';
-}
-
-/**
- * Form submit handler for field_ui_display_overview_form.
- * Stores which fields are published as blocks as a third_party_settings array
- * in the EntityViewDisplay object of the entity type / bundle / view mode.
- *
- * @param mixed[] $form
- *   A form API array.
- * @param \Drupal\Core\Form\FormStateInterface $form_state
- *   The state of the submitted form.
- */
-function fieldblock_field_display_submit($form, FormStateInterface $form_state) {
-  $entity_type = $form['#entity_type'];
-  $bundle = $form['#bundle'];
-  $mode = $form['#mode'];
-
-  /** @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface $entity_view_display */
-  $entity_view_display = EntityViewDisplay::load($entity_type . '.' . $bundle . '.' . $mode);
-
-  $fields = $form_state->getValue('fields');
-  foreach ($fields as $field_name => $field) {
-    if (isset($field['fieldblock']) && $field['fieldblock'] == 1) {
-      $entity_view_display->setThirdPartySetting('fieldblock', $field_name, $form['fields'][$field_name]['human_name']['#markup']);
-    }
-    else if ($entity_view_display->getThirdPartySetting('fieldblock', $field_name)) {
-      $entity_view_display->unsetThirdPartySetting('fieldblock', $field_name);
-    }
-  }
-  $entity_view_display->save();
-
-  // Invalidate the block cache to update fielblock derivatives.
-  if (\Drupal::moduleHandler()->moduleExists('block')) {
-    \Drupal::service('plugin.manager.block')->clearCachedDefinitions();
-  }
-}
-
-/**
- * Implements hook_entity_view_alter().
- *
- * Takes fields out of the current entity and caches them in a post render cache
- * context. The #post_render_cache callback makes this data available to the
- * fieldblock when it is built, We also hide the field from the render array.
- *
- * @param array &$build
- *   A renderable array representing the entity content.
- * @param \Drupal\Core\Entity\EntityInterface $entity
- *   The entity object being rendered. Not used in this implementation.
- * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
- *   The entity view display holding the display options configured for the
- *   entity components.
- *
- * @see \Drupal\fieldblock\Plugin\Block\FieldBlock::fieldBlockPostRenderCache
- * @see https://www.drupal.org/node/2151609
- */
-function fieldblock_entity_view_alter(array &$build, $entity, EntityViewDisplayInterface $display) {
-  $fieldblock_settings = $display->getThirdPartySettings('fieldblock');
-  $display_id = $display->get('id');
-
-  foreach ($fieldblock_settings as $field_name => $field_label) {
-    $fieldblock_id = $display_id . ':' . $field_name;
-
-    if (count(\Drupal\Core\Render\Element::children($build[$field_name]))) {
-      // This is where we take out the field and cache it in a post render
-      // cache context.
-      $build['#post_render_cache']['Drupal\fieldblock\Plugin\Block\FieldBlock::fieldBlockPostRenderCache'][] = array(
-        'build' => $build[$field_name],
-        'fieldblock_id' => $fieldblock_id,
-      );
-      hide($build[$field_name]);
-    }
-  }
-}
diff --git a/schema/fieldblock.schema.yml b/schema/fieldblock.schema.yml
new file mode 100644
index 0000000000000000000000000000000000000000..0358d19d1ad72800f36b0459dcfe2f4e768a2682
--- /dev/null
+++ b/schema/fieldblock.schema.yml
@@ -0,0 +1,18 @@
+# Schema for the configuration files of the Field as Block module.
+
+block.settings.fieldblock:*:
+  type: block_settings
+  label: 'Field as Block'
+  mapping:
+    label_from_field:
+      type: boolean
+      lable: 'Use field label as block title'
+    field_name:
+      type: string
+      label: 'Field name'
+    formatter_id:
+      type: string
+      label: 'Format type machine name'
+    formatter_settings:
+      type: field.formatter.settings.[%parent.formatter_id]
+      label: 'Settings'
diff --git a/src/Plugin/Block/FieldBlock.php b/src/Plugin/Block/FieldBlock.php
index fd769bbf69d20bc47672e83fd77e2a0b03f88158..477877b7ccc3289111a2f5bc8ebe01c83b970b95 100644
--- a/src/Plugin/Block/FieldBlock.php
+++ b/src/Plugin/Block/FieldBlock.php
@@ -6,82 +6,358 @@
  */
 
 namespace Drupal\fieldblock\Plugin\Block;
+
+use Drupal\Core\Access\AccessResult;
 use Drupal\Core\Block\BlockBase;
+use Drupal\Core\Entity\ContentEntityInterface;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Field\BaseFieldDefinition;
+use Drupal\Core\Field\FieldDefinitionInterface;
+use Drupal\Core\Field\FormatterInterface;
+use Drupal\Core\Field\FormatterPluginManager;
+use Drupal\Core\Form\FormHelper;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\Core\Session\AccountInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Provides a fieldblock.
  *
  * @Block(
  *   id = "fieldblock",
- *   admin_label = @Translation("Fieldblock"),
- *   deriver = "Drupal\fieldblock\Plugin\Derivative\FieldBlock"
+ *   admin_label = @Translation("Field as Block"),
+ *   deriver = "Drupal\fieldblock\Plugin\Derivative\FieldBlockDeriver"
  * )
  */
-class FieldBlock extends BlockBase {
+class FieldBlock extends BlockBase implements ContainerFactoryPluginInterface {
+
+  /**
+   * The entity manager.
+   *
+   * @var \Drupal\Core\Entity\EntityManagerInterface
+   */
+  protected $entityManager;
+
+  /**
+   * The field formatter plugin manager.
+   *
+   * @var \Drupal\Core\Field\FormatterPluginManager
+   */
+  protected $formatterPluginManager;
+
+  /**
+   * The current route match.
+   *
+   * @var \Drupal\Core\Routing\RouteMatchInterface
+   */
+  protected $routeMatch;
 
   /**
    * {@inheritdoc}
+   *
+   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
+   *   The entity manager.
+   * @param \Drupal\Core\Field\FormatterPluginManager $formatter_plugin_manager
+   *   The field formatter plugin manager.
+   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
+   *   The current route match.
    */
-  public function build() {
-    $block_id = $this->getDerivativeId();
-    $block = $this::getFieldBlock($block_id);
-    return $block;
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager, FormatterPluginManager $formatter_plugin_manager, RouteMatchInterface $route_match) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+    $this->entityManager = $entity_manager;
+    $this->formatterPluginManager = $formatter_plugin_manager;
+    $this->routeMatch = $route_match;
   }
 
   /**
-   * @var array[]
-   *   Static storage for fields that are grabbed from the entity's render
-   *   array, to be retrieved when fieldblocks are built.
+   * {@inheritdoc}
    */
-  protected static $fieldBlocks;
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static($configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get('entity.manager'),
+      $container->get('plugin.manager.field.formatter'),
+      $container->get('current_route_match'));
+  }
 
   /**
-   * @param string $fieldblock_id
-   *   The identifier of the fieldblock.
-   * @return mixed[]|false
-   *   The render array of the field that is published as block or false if the
-   *   field is not available.
+   * {@inheritdoc}
    */
-  public static function getFieldBlock($fieldblock_id) {
-    if (isset(self::$fieldBlocks[$fieldblock_id])) {
-      return self::$fieldBlocks[$fieldblock_id];
+  public function defaultConfiguration() {
+    return [
+      'label_from_field' => TRUE,
+      'field_name' => '',
+      'formatter_id' => '',
+      'formatter_settings' => []
+    ];
+  }
+
+  protected function getFieldOptions() {
+    $field_definitions = $this->entityManager->getFieldStorageDefinitions($this->getDerivativeId());
+    $options = [];
+    foreach ($field_definitions as $definition) {
+      $options[$definition->getName()] = $definition->getLabel();
+    }
+    return $options;
+  }
+
+  protected function getFormatterOptions(FieldDefinitionInterface $field_definition) {
+    $options = $this->formatterPluginManager->getOptions($field_definition->getType());
+    foreach ($options as $id => $label) {
+      $definition = $this->formatterPluginManager->getDefinition($id, FALSE);
+      $formatter_plugin_class = isset($definition['class']) ? $definition['class'] : NULL;
+      $applicable = $formatter_plugin_class instanceof FormatterInterface && $formatter_plugin_class::isApplicable($field_definition);
+      if ($applicable) {
+        unset($options[$id]);
+      }
     }
-    else {
-      return FALSE;
+    return $options;
+  }
+
+  /**
+   * Gets the field definition.
+   *
+   * A FieldBlock works on an entity type across bundles, and thus only has access to
+   * field storage definitions. In order to be able to use formatters, we create a
+   * generic field definition out of that storage definition.
+   *
+   * @param string $field_name
+   *
+   * @see BaseFieldDefinition::createFromFieldStorageDefinition()
+   * @see \Drupal\views\Plugin\views\field\Field::getFieldDefinition()
+   *
+   * @return \Drupal\Core\Field\FieldDefinitionInterface
+   *   The field definition used by this block.
+   */
+  protected function getFieldDefinition($field_name) {
+    $field_storage_config = $this->getFieldStorageDefinition($field_name);
+    return BaseFieldDefinition::createFromFieldStorageDefinition($field_storage_config);
+  }
+
+  /**
+   * Gets the field storage definition.
+   *
+   * @param string $field_name
+   *
+   * @return \Drupal\field\FieldStorageConfigInterface
+   *   The field storage definition used by this block.
+   */
+  protected function getFieldStorageDefinition($field_name) {
+    $field_storage_definitions = $this->entityManager->getFieldStorageDefinitions($this->getDerivativeId());
+    return $field_storage_definitions[$field_name];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function blockForm($form, FormStateInterface $form_state) {
+    $form['label_from_field'] = [
+      '#title' => $this->t('Use field label as block title'),
+      '#type' => 'checkbox',
+      '#default_value' => $this->configuration['label_from_field'],
+    ];
+
+    $form['field_name'] = [
+      '#title' => $this->t('Field'),
+      '#type' => 'select',
+      '#options' => $this->getFieldOptions(),
+      '#default_value' => $this->configuration['field_name'],
+      '#required' => TRUE,
+      '#ajax' => [
+        'callback' => [$this, 'blockFormChangeFieldOrFormatterAjax'],
+        'wrapper' => 'edit-block-formatter-wrapper',
+      ],
+    ];
+
+    $form['formatter'] = [
+      '#type' => 'container',
+      '#id' => 'edit-block-formatter-wrapper'
+    ];
+
+    $field_name = $form_state->getValue(['settings', 'field_name'], $this->configuration['field_name']);
+    $field_definition = NULL;
+    $formatter_id = $form_state->getValue(['settings', 'formatter', 'id'], $this->configuration['formatter_id']);
+
+    if ($field_name) {
+      $field_definition = $this->getFieldDefinition($field_name);
+      $formatter_options = $this->getFormatterOptions($field_definition);
+      if (empty($formatter_options)) {
+        $formatter_id = '';
+      }
+      else {
+        if (empty($formatter_id)) {
+          $formatter_id = reset($formatter_options);
+        }
+        $form['formatter']['id'] = [
+          '#title' => $this->t('Formatter'),
+          '#type' => 'select',
+          '#options' => $formatter_options,
+          '#default_value' => $this->configuration['formatter_id'],
+          '#required' => TRUE,
+          '#ajax' => [
+            'callback' => [$this, 'blockFormChangeFieldOrFormatterAjax'],
+            'wrapper' => 'edit-block-formatter-wrapper',
+          ],
+        ];
+      }
+    }
+
+    $form['formatter']['change'] = [
+      '#type' => 'submit',
+      '#name' => 'fieldblock_change_field',
+      '#value' => $this->t('Change field'),
+      '#attributes' => ['class' => ['js-hide']],
+      '#limit_validation_errors' => [['settings']],
+      '#submit' => [[get_class($this), 'blockFormChangeFieldOrFormatter']],
+    ];
+
+    if ($formatter_id) {
+      $formatter_settings = $this->configuration['formatter_settings'] + $this->formatterPluginManager->getDefaultSettings($formatter_id);
+      $formatter_options = [
+        'field_definition' => $field_definition,
+        'view_mode' => '_custom',
+        'configuration' => [
+          'type' => $formatter_id,
+          'settings' => $formatter_settings,
+          'label' => '',
+          'weight' => 0,
+        ]
+      ];
+
+      if ($formatter_plugin = $this->formatterPluginManager->getInstance($formatter_options)) {
+        $formatter_settings_form = $formatter_plugin->settingsForm($form, $form_state);
+        // Convert field UI selector states to work in the block configuration form.
+        FormHelper::rewriteStatesSelector($formatter_settings_form,
+          "fields[{$field_name}][settings_edit_form]",
+          'settings[formatter][settings]');
+      }
+      if (!empty($formatter_settings_form)) {
+        $form['formatter']['settings'] = $formatter_settings_form;
+        $form['formatter']['settings']['#type'] = 'fieldset';
+        $form['formatter']['settings']['#title'] = $this->t('Formatter settings');
+      }
     }
+
+    return $form;
   }
 
   /**
-   * @param string $fieldblock_id
-   *   The identifier of the fieldblock.
-   * @param mixed[] $render_array
-   *   The render array of the field that will be published as block.
+   * Element submit handler for non-JS field/formatter changes.
+   *
+   * @param array $form
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    */
-  public static function setFieldBlock($fieldblock_id, array $render_array) {
-    self::$fieldBlocks[$fieldblock_id] = $render_array;
+  public static function blockFormChangeFieldOrFormatter(array $form, FormStateInterface $form_state) {
+    $form_state->setRebuild();
   }
 
   /**
-   * #post_render_cache callback, temporarily stores a field's render array in a
-   * static variable and returns the original element as post render cache
-   * callbacks are supposed to do.
+   * Ajax callback on changing field_name or formatter_id form element.
    *
-   * Note that this is an atypical way to use the post render cache mechanism.
-   * Post render cache is meant to allow modules to dynamically alter pieces of
-   * cached content. Here we use it as some kind of context-aware cache, because
-   * the cached field will only be retrieved and displayed as a block when the
-   * entity is viewed.
+   * @param $form
    *
-   * @param mixed[] $element
-   *   The render array being rendered.
-   * @param mixed[] $context
-   *   Array containing the fieldblock ID and the field's render array.
-   * @return mixed[]
-   *   The render array being rendered.
+   * @return array
+   *   The part of the form that has changed.
+   */
+  public function blockFormChangeFieldOrFormatterAjax($form) {
+    return $form['settings']['formatter'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function blockValidate($form, FormStateInterface $form_state) {
+    parent::blockValidate($form, $form_state);
+  }
+
+  /**
+   * {@inheritdoc}
    */
-  public static function fieldBlockPostRenderCache(array $element, array $context) {
-    self::setFieldBlock($context['fieldblock_id'], $context['build']);
-    return $element;
+  public function blockSubmit($form, FormStateInterface $form_state) {
+    $this->configuration['label_from_field'] = $form_state->getValue('label_from_field');
+    $this->configuration['field_name'] = $form_state->getValue('field_name');
+    $this->configuration['formatter_id'] = $form_state->getValue(['formatter', 'id'], '');
+    $this->configuration['formatter_settings'] = $form_state->getValue(['formatter', 'settings'], []);
   }
 
+  /**
+   * {@inheritdoc}
+   *
+   * @see \Drupal\views\Plugin\views\field\Field::calculateDependencies()
+   */
+  public function calculateDependencies() {
+    $dependencies = parent::calculateDependencies();
+
+    // Add the module providing the configured field storage as a dependency.
+    if (($field_storage_definition = $this->getFieldStorageDefinition($this->configuration['field_name'])) && $field_storage_definition instanceof EntityInterface) {
+      $dependencies['config'][] = $field_storage_definition->getConfigDependencyName();
+    }
+    // Add the module providing the formatter.
+    if (!empty($this->configuration['formatter_id'])) {
+      $dependencies['module'][] = $this->formatterPluginManager->getDefinition($this->configuration['formatter_id'])['provider'];
+    }
+
+    return $dependencies;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function blockAccess(AccountInterface $account) {
+    $entity_type = $this->getDerivativeId();
+    $entity = $this->routeMatch->getParameter($entity_type);
+
+    if ($entity instanceof ContentEntityInterface && $entity->getEntityTypeId() === $entity_type && $entity->hasField($this->configuration['field_name'])) {
+      $field = $entity->get($this->configuration['field_name']);
+      return AccessResult::allowedIf(!$field->isEmpty() && $field->access('view', $account));
+    }
+    return AccessResult::forbidden();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function build() {
+    $build = [];
+    $entity_type = $this->getDerivativeId();
+    $entity = $this->routeMatch->getParameter($entity_type);
+
+    if ($entity instanceof ContentEntityInterface) {
+      $build['field'] = $entity->get($this->configuration['field_name'])->view([
+        'label' => 'hidden',
+        'type' => $this->configuration['formatter_id'],
+        'settings' => $this->configuration['formatter_settings']
+      ]);
+      if ($this->configuration['label_from_field'] && !empty($build['field']['#title'])) {
+        $build['#title'] = $build['field']['#title'];
+      }
+    }
+
+    return $build;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheTags() {
+    $entity_type = $this->getDerivativeId();
+    $entity = $this->routeMatch->getParameter($entity_type);
+    if ($entity instanceof ContentEntityInterface) {
+      return $entity->getCacheTags();
+    }
+    return parent::getCacheTags();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheContexts() {
+    // This block must be cached per URL: every entity has its own canonical url
+    // and its own fields.
+    return ['url'];
+  }
 }
diff --git a/src/Plugin/Derivative/FieldBlock.php b/src/Plugin/Derivative/FieldBlock.php
index 0d5a670a58a06252d057554e269fbb9429e5511d..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644
--- a/src/Plugin/Derivative/FieldBlock.php
+++ b/src/Plugin/Derivative/FieldBlock.php
@@ -1,105 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\fieldblock\Plugin\Derivative\FieldBlock.
- */
-
-namespace Drupal\fieldblock\Plugin\Derivative;
-
-use Drupal\Component\Plugin\Derivative\DeriverBase;
-use Drupal\Core\Entity\EntityManagerInterface;
-use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
-use Drupal\Core\StringTranslation\StringTranslationTrait;
-use Drupal\Core\StringTranslation\TranslationInterface;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-
-/**
- * Provides block plugin definitions for fieldblock blocks.
- *
- * @see \Drupal\fieldblock\Plugin\Block\FieldBlock
- */
-class FieldBlock extends DeriverBase implements ContainerDeriverInterface {
-
-  use StringTranslationTrait;
-
-  /**
-   * The entity view display storage.
-   *
-   * @var \Drupal\Core\Entity\EntityStorageInterface
-   */
-  protected $entityViewDisplayStorage;
-
-  /**
-   * Constructs a FieldBlock deriver object.
-   *
-   * @param \Drupal\Core\Entity\Entity\EntityViewDisplay $entity_view_display
-   *   The entity view display storage.
-   * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
-   *   The string translation.
-   */
-  public function __construct($entity_view_display, TranslationInterface $string_translation) {
-    $this->entityViewDisplayStorage = $entity_view_display;
-    $this->stringTranslation = $string_translation;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container, $base_plugin_id) {
-    /** @var EntityManagerInterface $entity_manager */
-    $entity_manager = $container->get('entity.manager');
-    return new static(
-      $entity_manager->getStorage('entity_view_display'),
-      $container->get('string_translation')
-    );
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getDerivativeDefinitions($base_plugin_definition) {
-    $blocks = $this->fieldBlockGetBlockList();
-
-    foreach ($blocks as $fieldblock_id => $description) {
-      $this->derivatives[$fieldblock_id] = $base_plugin_definition;
-      $this->derivatives[$fieldblock_id]['admin_label'] = $description;
-    }
-
-    return $this->derivatives;
-  }
-
-  /**
-   * Builds a list of fields that have been made available as a block.
-   *
-   * @return string[]
-   *   An array of fieldblocks in the form of fieldblock_id => admin label.
-   */
-  protected function fieldBlockGetBlockList() {
-    $fieldblocks = array();
-
-    // Get all EntityViewDisplay config entities and iterate over them.
-    $entity_view_displays = $this->entityViewDisplayStorage->loadMultiple();
-
-    /** @var \Drupal\Core\Entity\EntityDisplayModeInterface $entity_view_display */
-    foreach ($entity_view_displays as $display_id => $entity_view_display) {
-      $view_display_fieldblocks = $entity_view_display->getThirdPartySettings('fieldblock');
-      $entity_type = $entity_view_display->get('targetEntityType');
-      $bundle = $entity_view_display->get('bundle');
-      $mode = $entity_view_display->get('mode');
-
-      foreach ($view_display_fieldblocks as $field_name => $field_label) {
-        $fieldblock_id = $display_id . ':' . $field_name;
-        $fieldblocks[$fieldblock_id] = $this->t('@field field (from @type: @bundle: @mode)', array(
-          '@field' => $field_label,
-          '@type' => $entity_type,
-          '@bundle' => $bundle,
-          '@mode' => $mode,
-        ));
-      }
-    }
-
-    return $fieldblocks;
-  }
-
-}
diff --git a/src/Plugin/Derivative/FieldBlockDeriver.php b/src/Plugin/Derivative/FieldBlockDeriver.php
new file mode 100644
index 0000000000000000000000000000000000000000..3c814b0fa95060014ae5a2ec69a25b8ec15bc37b
--- /dev/null
+++ b/src/Plugin/Derivative/FieldBlockDeriver.php
@@ -0,0 +1,69 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\fieldblock\Plugin\Derivative\FieldBlockDeriver.
+ */
+
+namespace Drupal\fieldblock\Plugin\Derivative;
+
+use Drupal\Component\Plugin\Derivative\DeriverBase;
+use Drupal\Core\Entity\ContentEntityTypeInterface;
+use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides block plugin definitions for fieldblock blocks.
+ *
+ * @see \Drupal\fieldblock\Plugin\Block\FieldBlock
+ */
+class FieldBlockDeriver extends DeriverBase implements ContainerDeriverInterface {
+
+  use StringTranslationTrait;
+
+  /**
+   * The entity manager.
+   *
+   * @var \Drupal\Core\Entity\EntityManagerInterface
+   */
+  protected $entityManager;
+
+  /**
+   * Constructs a FieldBlockDeriver object.
+   *
+   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
+   *   The entity manager.
+   */
+  public function __construct(EntityManagerInterface $entity_manager) {
+    $this->entityManager = $entity_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, $base_plugin_id) {
+    return new static(
+      $container->get('entity.manager')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDerivativeDefinitions($base_plugin_definition) {
+    $definitions = $this->entityManager->getDefinitions();
+
+    foreach ($definitions as $entity_type_id => $definition) {
+      if ($definition instanceof ContentEntityTypeInterface) {
+        $this->derivatives[$entity_type_id] = $base_plugin_definition;
+        $this->derivatives[$entity_type_id]['admin_label'] = $this->t('@type field', [
+          '@type' => $definition->getLabel(),
+        ]);
+      }
+    }
+
+    return $this->derivatives;
+  }
+}