diff --git a/block_field.services.yml b/block_field.services.yml
index f8bdc23..1e7f719 100755
--- a/block_field.services.yml
+++ b/block_field.services.yml
@@ -2,3 +2,6 @@ services:
   block_field.manager:
     class: Drupal\block_field\BlockFieldManager
     arguments: ['@plugin.manager.block', '@context.repository']
+  plugin.manager.block_field_selection:
+    class: Drupal\block_field\BlockFieldSelectionManager
+    parent: default_plugin_manager
diff --git a/src/BlockFieldManager.php b/src/BlockFieldManager.php
index 87a5166..44f5937 100644
--- a/src/BlockFieldManager.php
+++ b/src/BlockFieldManager.php
@@ -45,4 +45,12 @@ class BlockFieldManager implements BlockFieldManagerInterface {
     return $this->blockManager->getSortedDefinitions($definitions);
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getBlockCategories() {
+      return $this->blockManager->getCategories();
+  }
+
+
 }
diff --git a/src/BlockFieldManagerInterface.php b/src/BlockFieldManagerInterface.php
index e57580f..8d20864 100644
--- a/src/BlockFieldManagerInterface.php
+++ b/src/BlockFieldManagerInterface.php
@@ -15,4 +15,12 @@ interface BlockFieldManagerInterface {
    */
   public function getBlockDefinitions();
 
+  /**
+   * Get list of all block categories.
+   *
+   * @return string[]
+   *   A numerically indexed array of block categories.
+   */
+  public function getBlockCategories();
+
 }
diff --git a/src/Plugin/Field/FieldType/BlockFieldItem.php b/src/Plugin/Field/FieldType/BlockFieldItem.php
index 80634e1..1585a62 100644
--- a/src/Plugin/Field/FieldType/BlockFieldItem.php
+++ b/src/Plugin/Field/FieldType/BlockFieldItem.php
@@ -3,9 +3,11 @@
 namespace Drupal\block_field\Plugin\Field\FieldType;
 
 use Drupal\block_field\BlockFieldItemInterface;
+use Drupal\Console\Core\Utils\NestedArray;
 use Drupal\Core\Field\FieldItemBase;
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Render\Element;
 use Drupal\Core\TypedData\DataDefinition;
 use Drupal\Core\TypedData\MapDataDefinition;
 
@@ -28,8 +30,9 @@ class BlockFieldItem extends FieldItemBase implements BlockFieldItemInterface {
    */
   public static function defaultFieldSettings() {
     return [
-      'plugin_ids' => [],
-    ] + parent::defaultFieldSettings();
+        'selection' => 'blocks',
+        'selection_settings' => [],
+      ] + parent::defaultFieldSettings();
   }
 
   /**
@@ -81,42 +84,51 @@ class BlockFieldItem extends FieldItemBase implements BlockFieldItemInterface {
   public function fieldSettingsForm(array $form, FormStateInterface $form_state) {
     $field = $form_state->getFormObject()->getEntity();
 
-    /** @var \Drupal\block_field\BlockFieldManagerInterface $block_field_manager */
-    $block_field_manager = \Drupal::service('block_field.manager');
-    $definitions = $block_field_manager->getBlockDefinitions();
-    foreach ($definitions as $plugin_id => $definition) {
-      $options[$plugin_id] = [
-        ['category' => (string) $definition['category']],
-        ['label' => $definition['admin_label'] . ' (' . $plugin_id . ')'],
-        ['provider' => $definition['provider']],
-      ];
-    }
-
-    $default_value = $field->getSetting('plugin_ids') ?: array_keys($options);
+    /** @var \Drupal\block_field\BlockFieldSelectionManager $block_field_selection_manager */
+    $block_field_selection_manager = \Drupal::service('plugin.manager.block_field_selection');
+    $options = $block_field_selection_manager->getOptions();
+    $form = [
+      '#type' => 'container',
+      '#process' => [[get_class($this), 'fieldSettingsAjaxProcess']],
+      '#element_validate' => [[get_class($this), 'fieldSettingsFormValidate']],
 
-    $element = [];
-    $element['blocks'] = [
+    ];
+    $form['selection'] = [
       '#type' => 'details',
-      '#title' => $this->t('Blocks'),
-      '#description' => $this->t('Please select available blocks.'),
-      '#open' => $field->getSetting('plugin_ids') ? TRUE : FALSE,
+      '#title' => t('Available blocks'),
+      '#open' => TRUE,
+      '#tree' => TRUE,
+      '#process' => [[get_class($this), 'formProcessMergeParent']],
     ];
-    $element['blocks']['plugin_ids'] = [
-      '#type' => 'tableselect',
-      '#header' => [
-        'Category',
-        'Label/ID',
-        'Provider',
-      ],
+
+    $form['selection']['selection'] = [
+      '#type' => 'select',
+      '#title' => t('Selection method'),
       '#options' => $options,
-      '#js_select' => TRUE,
+      '#default_value' => $field->getSetting('selection'),
       '#required' => TRUE,
-      '#empty' => t('No blocks are available.'),
-      '#parents' => ['settings', 'plugin_ids'],
-      '#element_validate' => [[get_called_class(), 'validatePluginIds']],
-      '#default_value' => array_combine($default_value, $default_value),
+      '#ajax' => TRUE,
+      '#limit_validation_errors' => [],
     ];
-    return $element;
+    $form['selection']['selection_submit'] = [
+      '#type' => 'submit',
+      '#value' => t('Change selection'),
+      '#limit_validation_errors' => [],
+      '#attributes' => [
+        'class' => ['js-hide'],
+      ],
+      '#submit' => [[get_class($this), 'settingsAjaxSubmit']],
+    ];
+
+    $form['selection']['selection_settings'] = [
+      '#type' => 'container',
+      '#attributes' => ['class' => ['block_field-settings']],
+    ];
+
+    $selection = $block_field_selection_manager->getSelectionHandler($field);
+    $form['selection']['selection_settings'] += $selection->buildConfigurationForm([], $form_state);
+
+    return $form;
   }
 
   /**
@@ -194,4 +206,77 @@ class BlockFieldItem extends FieldItemBase implements BlockFieldItemInterface {
     return $element;
   }
 
+  /**
+   * Render API callback: Processes the field settings form and allows access to
+   * the form state.
+   *
+   * @see static::fieldSettingsForm()
+   */
+  public static function fieldSettingsAjaxProcess($form, FormStateInterface $form_state) {
+    static::fieldSettingsAjaxProcessElement($form, $form);
+    return $form;
+  }
+
+  /**
+   * Adds block_field specific properties to AJAX form elements from the
+   * field settings form.
+   *
+   * @see static::fieldSettingsAjaxProcess()
+   */
+  public static function fieldSettingsAjaxProcessElement(&$element, $main_form) {
+    if (!empty($element['#ajax'])) {
+      $element['#ajax'] = [
+        'callback' => [get_called_class(), 'settingsAjax'],
+        'wrapper' => $main_form['#id'],
+        'element' => $main_form['#array_parents'],
+      ];
+    }
+
+    foreach (Element::children($element) as $key) {
+      static::fieldSettingsAjaxProcessElement($element[$key], $main_form);
+    }
+  }
+
+  /**
+   * Ajax callback for the selection settings form.
+   *
+   * @see static::fieldSettingsForm()
+   */
+  public static function settingsAjax($form, FormStateInterface $form_state) {
+    return NestedArray::getValue($form, $form_state->getTriggeringElement()['#ajax']['element']);
+  }
+  /**
+   * Submit selection for the non-JS case.
+   *
+   * @see static::fieldSettingsForm()
+   */
+  public static function settingsAjaxSubmit($form, FormStateInterface $form_state) {
+    $form_state->setRebuild();
+  }
+
+  /**
+   * Render API callback: Moves block_field specific Form API elements
+   * (i.e. 'selection_settings') up a level for easier processing by the
+   * validation and submission selections.
+   */
+  public static function formProcessMergeParent($element) {
+    $parents = $element['#parents'];
+    array_pop($parents);
+    $element['#parents'] = $parents;
+    return $element;
+  }
+
+  /**
+   * Form element validation handler; Invokes selection plugin's validation.
+   *
+   * @param array $form
+   *   The form where the settings form is being included in.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The form state of the (entire) configuration form.
+   */
+  public static function fieldSettingsFormValidate(array $form, FormStateInterface $form_state) {
+    $field = $form_state->getFormObject()->getEntity();
+    $handler = \Drupal::service('plugin.manager.block_field_selection')->getSelectionHandler($field);
+    $handler->validateConfigurationForm($form, $form_state);
+  }
 }
diff --git a/src/Plugin/Field/FieldWidget/BlockFieldWidget.php b/src/Plugin/Field/FieldWidget/BlockFieldWidget.php
index 90c5123..f88671b 100644
--- a/src/Plugin/Field/FieldWidget/BlockFieldWidget.php
+++ b/src/Plugin/Field/FieldWidget/BlockFieldWidget.php
@@ -2,8 +2,10 @@
 
 namespace Drupal\block_field\Plugin\Field\FieldWidget;
 
+use Drupal\block_field\BlockFieldSelectionManager;
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Block\BlockManagerInterface;
+use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
 use Drupal\Core\Form\FormState;
@@ -32,6 +34,12 @@ class BlockFieldWidget extends WidgetBase implements ContainerFactoryPluginInter
    * @var \Drupal\Core\Block\BlockManagerInterface
    */
   protected $blockManager;
+  /**
+   * The block field selection manager.
+   *
+   * @var \Drupal\block_field\BlockFieldSelectionManager
+   */
+  protected $blockFieldSelectionManager;
 
   /**
    * Set the block manager.
@@ -52,13 +60,36 @@ class BlockFieldWidget extends WidgetBase implements ContainerFactoryPluginInter
       $plugin_definition,
       $configuration['field_definition'],
       $configuration['settings'],
-      $configuration['third_party_settings']
+      $configuration['third_party_settings'],
+      $container->get('plugin.manager.block_field_selection')
     );
     $instance->setBlockManager($container->get('plugin.manager.block'));
 
     return $instance;
   }
 
+  /**
+   * Constructs a WidgetBase object.
+   *
+   * @param string $plugin_id
+   *   The plugin_id for the widget.
+   * @param mixed $plugin_definition
+   *   The plugin implementation definition.
+   * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
+   *   The definition of the field to which the widget is associated.
+   * @param array $settings
+   *   The widget settings.
+   * @param array $third_party_settings
+   *   Any third party settings.
+   * @param \Drupal\block_field\BlockFieldSelectionManager $block_field_selection_manager
+   */
+  public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, array $third_party_settings, BlockFieldSelectionManager $block_field_selection_manager) {
+    parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $third_party_settings);
+    $this->fieldDefinition = $field_definition;
+    $this->settings = $settings;
+    $this->thirdPartySettings = $third_party_settings;
+    $this->blockFieldSelectionManager = $block_field_selection_manager;
+  }
   /**
    * {@inheritdoc}
    */
@@ -121,28 +152,15 @@ class BlockFieldWidget extends WidgetBase implements ContainerFactoryPluginInter
       $item->settings = $item->settings ?: [];
     }
 
-    $options = [];
-    /** @var \Drupal\block_field\BlockFieldManagerInterface $block_field_manager */
-    $block_field_manager = \Drupal::service('block_field.manager');
-    $definitions = $block_field_manager->getBlockDefinitions();
-    foreach ($definitions as $id => $definition) {
-      // If allowed plugin ids are set then check that this block should be
-      // included.
-      if ($plugin_ids && !isset($plugin_ids[$id])) {
-        // Remove the definition, so that we have an accurate list of allowed
-        // blocks definitions.
-        unset($definitions[$id]);
-        continue;
+    $options = $this->blockFieldSelectionManager->getWidgetOptions($this->fieldDefinition);
+    if ($item->plugin_id) {
+      // If plugin_id not in second level arrays, unset plugin_id and settings..
+      if(!in_array($item->plugin_id, array_keys(call_user_func_array('array_merge', $options)), true)) {
+        $item->plugin_id = '';
+        $item->setting = [];
       }
-      $category = (string) $definition['category'];
-      $options[$category][$id] = $definition['admin_label'];
     }
 
-    // Make sure the plugin id is allowed, if not clear all settings.
-    if ($item->plugin_id && !isset($definitions[$item->plugin_id])) {
-      $item->plugin_id = '';
-      $item->setting = [];
-    }
 
     $element['plugin_id'] = [
       '#type' => 'select',
