diff --git a/config/schema/per_user_block.schema.yml b/config/schema/per_user_block.schema.yml
index 350b838..74e34e6 100644
--- a/config/schema/per_user_block.schema.yml
+++ b/config/schema/per_user_block.schema.yml
@@ -1,6 +1,7 @@
-condition.plugin.per_user:
-  type: condition.plugin
+block.block.*.third_party.per_user_block:
+  type: mapping
+  label: 'Per User Block settings'
   mapping:
-    custom:
-      label: 'Block setting'
+    visibility:
       type: integer
+      label: 'Block visibility setting'
diff --git a/js/per_user_block.js b/js/per_user_block.js
index 4a1148a..16c858c 100644
--- a/js/per_user_block.js
+++ b/js/per_user_block.js
@@ -1,21 +1,21 @@
 (function ($, window) {
 
-"use strict";
+  "use strict";
 
-    Drupal.behaviors.perUserBlockSettingsSummary = {
-      attach: function() {
-          // @todo Investigate if we still need this.
-          // The drupalSetSummary method required for this behavior is not available
-          // on the Blocks administration page, so we need to make sure this
-          // behavior is processed only if drupalSetSummary is defined.
-          if (typeof jQuery.fn.drupalSetSummary === 'undefined') {
-              return;
-          }
-
-          $("#edit-visibility-per-user").drupalSetSummary(function(context) {
-              return $(context).find('input[type="radio"]:checked + label').text();
-          });
+  Drupal.behaviors.perUserBlockSettingsSummary = {
+    attach: function () {
+      // @todo Investigate if we still need this.
+      // The drupalSetSummary method required for this behavior is not available
+      // on the Blocks administration page, so we need to make sure this
+      // behavior is processed only if drupalSetSummary is defined.
+      if (typeof jQuery.fn.drupalSetSummary === 'undefined') {
+        return;
       }
-    };
 
-})(jQuery, window);
\ No newline at end of file
+      $("#edit-third-party-settings-per-user-block").drupalSetSummary(function (context) {
+        return $(context).find('input[type="radio"]:checked + label').text();
+      });
+    }
+  };
+
+})(jQuery, window);
diff --git a/per_user_block.module b/per_user_block.module
index 0ae58bf..a0e0ec0 100644
--- a/per_user_block.module
+++ b/per_user_block.module
@@ -6,6 +6,9 @@
 
 use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\block\Entity\Block;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\Access\AccessResult;
 
 /**
  * Users cannot control whether or not they see this block.
@@ -22,6 +25,31 @@ define('PER_USER_BLOCK_CUSTOM_ENABLED', 1);
  */
 define('PER_USER_BLOCK_CUSTOM_DISABLED', 2);
 
+/**
+ * Implements hook_form_FORM_ID_alter().
+ */
+function per_user_block_form_block_form_alter(&$form, FormStateInterface $form_state) {
+  /** @var \Drupal\block\Entity\Block $block */
+  $block = $form_state->getFormObject()->getEntity();
+
+  $form['third_party_settings']['per_user_block'] = array(
+    '#type' => 'details',
+    '#title' => 'Per User',
+    '#group' => 'visibility_tabs',
+  );
+  $form['third_party_settings']['per_user_block']['visibility'] = array(
+    '#type' => 'radios',
+    '#title' => t('Customizable per user'),
+    '#description' => t('Allow individual users to customize the visibility of this block in their account settings.'),
+    '#default_value' => $block->getThirdPartySetting('per_user_block', 'visibility', PER_USER_BLOCK_CUSTOM_FIXED),
+    '#options' => array(
+      PER_USER_BLOCK_CUSTOM_FIXED => t('Not customizable'),
+      PER_USER_BLOCK_CUSTOM_ENABLED => t('Customizable, visible by default'),
+      PER_USER_BLOCK_CUSTOM_DISABLED => t('Customizable, hidden by default'),
+    ),
+  );
+  $form['#attached']['library'][] = 'per_user_block/per_user_block';
+}
 
 /**
  * Implements hook_form_FORM_ID_alter().
@@ -29,8 +57,8 @@ define('PER_USER_BLOCK_CUSTOM_DISABLED', 2);
 function per_user_block_form_user_form_alter(&$form, FormStateInterface $form_state) {
 
   // Load all the block info for the current default theme.
-  $theme = $default_theme = Drupal::config('system.theme')->get('default');
-  $entities = _block_rehash($theme);
+  $theme = $default_theme = \Drupal::config('system.theme')->get('default');
+  $entities = \Drupal::entityManager()->getStorage('block')->loadByProperties(['theme' => $theme]);
 
   // Load any existing user data.
   $account = $form_state->getFormObject()->getEntity();
@@ -40,8 +68,7 @@ function per_user_block_form_user_form_alter(&$form, FormStateInterface $form_st
   $options = array();
   /** @var \Drupal\block\BlockInterface $block */
   foreach ($entities as $entity_id => $block) {
-    $block_visibility = $block->getVisibility();
-    $block_visibility = isset($block_visibility['per_user']['custom']) ? $block_visibility['per_user']['custom'] : PER_USER_BLOCK_CUSTOM_FIXED;
+    $block_visibility = $block->getThirdPartySetting('per_user_block', 'visibility', PER_USER_BLOCK_CUSTOM_FIXED);
 
     // If this block is customisable by the user.
     if ($block_visibility != PER_USER_BLOCK_CUSTOM_FIXED) {
@@ -76,15 +103,39 @@ function per_user_block_form_user_form_alter(&$form, FormStateInterface $form_st
 function per_user_block_user_form_submit(&$form, FormStateInterface $form_state) {
   $account = $form_state->getFormObject()->getEntity();
   if ($account->id() && $form_state->getValue('blocks')) {
-    Drupal::service('user.data')->set('per_user_block', $account->id(), 'blocks', $form_state->getValue('blocks'));
+    \Drupal::service('user.data')->set('per_user_block', $account->id(), 'blocks', $form_state->getValue('blocks'));
   }
 }
 
 /**
- * Implements hook_entity_info_alter().
+ * Implements hook_block_access().
  */
-function per_user_block_entity_type_alter(array &$entity_types) {
-  /** @var \Drupal\Core\Config\Entity\ConfigEntityType[] $entity_types */
-  $entity_types['block']
-    ->setClass('Drupal\per_user_block\Entity\Block');
+function per_user_block_block_access(Block $block, $operation, AccountInterface $account, $langcode) {
+
+  $visibility = $block->getThirdPartySetting('per_user_block', 'visibility', PER_USER_BLOCK_CUSTOM_FIXED);
+
+  // If the block visibility can not be changed we have nothing to add.
+  if ($visibility == PER_USER_BLOCK_CUSTOM_FIXED) {
+    return;
+  }
+
+  // If it's an admin path we don't care. This is currently just so we don't
+  // impact the block overview page.
+  if (\Drupal::service('router.admin_context')->isAdminRoute()) {
+    return;
+  }
+
+  $user_block_settings = \Drupal::service('user.data')->get('per_user_block', $account->id(), 'blocks');
+
+  // Use the on/off flag stored in the user settings if they have one.
+  if (isset($user_block_settings[$block->id()])) {
+    // We store 0 if the block is disabled otherwise the block id.
+    $access = $user_block_settings[$block->id()] === 0;
+  }
+  else {
+    // Use the default selected visibility.
+    $access = $visibility != PER_USER_BLOCK_CUSTOM_ENABLED;
+  }
+
+  return AccessResult::forbiddenIf($access)->cachePerUser();
 }
diff --git a/per_user_block.services.yml b/per_user_block.services.yml
deleted file mode 100644
index 66c2bda..0000000
--- a/per_user_block.services.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-services:
-  per_user_block.block_context:
-    class: Drupal\per_user_block\EventSubscriber\BlockContext
-    tags:
-      - { name: 'event_subscriber' }
diff --git a/src/Entity/Block.php b/src/Entity/Block.php
deleted file mode 100644
index 14eb868..0000000
--- a/src/Entity/Block.php
+++ /dev/null
@@ -1,28 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\per_user_block\Entity\Block.
- */
-
-namespace Drupal\per_user_block\Entity;
-
-use Drupal\block\Entity\Block as CoreBlock;
-use Drupal\Core\Plugin\Context\Context;
-use Drupal\Core\Plugin\Context\ContextDefinition;
-
-class Block extends CoreBlock {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setContexts(array $contexts) {
-    // Store the name in the contexts array using a key that is used in our
-    // BlockContext subscriber.
-    $contexts['per_user_block.block'] = new Context(new ContextDefinition('entity:block'));
-    $contexts['per_user_block.block']->setContextValue($this);
-    $this->contexts = $contexts;
-    return $this;
-  }
-
-}
diff --git a/src/EventSubscriber/BlockContext.php b/src/EventSubscriber/BlockContext.php
deleted file mode 100644
index ddc5fac..0000000
--- a/src/EventSubscriber/BlockContext.php
+++ /dev/null
@@ -1,34 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\per_user_block\EventSubscriber\BlockContext
- */
-
-namespace Drupal\per_user_block\EventSubscriber;
-
-use Drupal\block\Event\BlockContextEvent;
-use Drupal\block\Event\BlockEvents;
-use Drupal\Core\Plugin\Context\Context;
-use Drupal\Core\Plugin\Context\ContextDefinition;
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-
-class BlockContext implements EventSubscriberInterface {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function onBlockAdministrativeContext(BlockContextEvent $event) {
-    $context = new Context(new ContextDefinition('entity:block'));
-    $event->setContext('per_user_block.block', $context);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function getSubscribedEvents() {
-    $events[BlockEvents::ADMINISTRATIVE_CONTEXT][] = 'onBlockAdministrativeContext';
-    return $events;
-  }
-
-}
diff --git a/src/Plugin/Condition/PerUser.php b/src/Plugin/Condition/PerUser.php
deleted file mode 100644
index 4c96845..0000000
--- a/src/Plugin/Condition/PerUser.php
+++ /dev/null
@@ -1,95 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\per_user_block\Plugin\Condition\PerUser.
- */
-
-namespace Drupal\per_user_block\Plugin\Condition;
-
-use Drupal\Core\Condition\ConditionPluginBase;
-use Drupal\Core\Form\FormStateInterface;
-
-/**
- * Provides a 'Per User' condition.
- *
- * @Condition(
- *   id = "per_user",
- *   label = @Translation("Per User"),
- *   context = {
- *     "user" = @ContextDefinition("entity:user", label = @Translation("User")),
- *     "block" = @ContextDefinition("entity:block", label = @Translation("Block"))
- *   }
- * )
- *
- */
-class PerUser extends ConditionPluginBase {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
-    $form['custom'] = array(
-      '#type' => 'radios',
-      '#title' => t('Customizable per user'),
-      '#description' => t('Allow individual users to customize the visibility of this block in their account settings.'),
-      '#default_value' => isset($this->configuration['custom']) ? $this->configuration['custom'] : PER_USER_BLOCK_CUSTOM_FIXED,
-      '#options' => array(
-        PER_USER_BLOCK_CUSTOM_FIXED => t('Not customizable'),
-        PER_USER_BLOCK_CUSTOM_ENABLED => t('Customizable, visible by default'),
-        PER_USER_BLOCK_CUSTOM_DISABLED => t('Customizable, hidden by default'),
-      ),
-    );
-    // Add our JS to display the default description on our vertical tab.
-    $form['#attached']['library'][] = 'per_user_block/per_user_block';
-    return parent::buildConfigurationForm($form, $form_state);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function defaultConfiguration() {
-    return array(
-      'custom' => PER_USER_BLOCK_CUSTOM_FIXED,
-    ) + parent::defaultConfiguration();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
-    $this->configuration['custom'] = $form_state->getValue('custom');
-    parent::submitConfigurationForm($form, $form_state);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function summary() {
-    return $this->configuration['custom'] == PER_USER_BLOCK_CUSTOM_FIXED ? t('Block is not customizable') : t('Block is customizable');
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  function evaluate() {
-    $visibility = $this->configuration['custom'];
-
-    // If the block position is fixed then it's always visible.
-    if ($visibility == PER_USER_BLOCK_CUSTOM_FIXED) {
-      return TRUE;
-    }
-
-    $block = $this->getContextValue('block');
-    $user_block_settings = \Drupal::service('user.data')->get('per_user_block', $this->getContextValue('user')->id(), 'blocks');
-
-    // Use the on/off flag stored in the user settings if they have one.
-    if (isset($user_block_settings[$block->id()])) {
-      return (bool) $user_block_settings[$block->id()];
-    }
-
-    // Use the default selected visibility.
-    return $visibility == PER_USER_BLOCK_CUSTOM_ENABLED;
-  }
-
-}
diff --git a/src/Tests/PerUserBlockOptionTest.php b/src/Tests/PerUserBlockOptionTest.php
index 02ba19f..f5dd328 100644
--- a/src/Tests/PerUserBlockOptionTest.php
+++ b/src/Tests/PerUserBlockOptionTest.php
@@ -62,17 +62,17 @@ class PerUserBlockOptionTest extends WebTestBase {
     // Get the Block manage page and ensure the settings exist.
     $block_path = 'admin/structure/block/manage/' . $block_id;
     $this->drupalGet($block_path);
-    $element = $this->xpath('//details[@id=:id]/*', array(':id' => 'edit-visibility-per-user'));
+    $element = $this->xpath('//details[@id=:id]/*', array(':id' => 'edit-third-party-settings-per-user-block'));
     $this->assertTrue(!empty($element), 'Per user block visibility settings exist.');
 
     // Change the value to disabled and validate it was saved.
     $edit = array();
-    $edit['visibility[per_user][custom]'] = PER_USER_BLOCK_CUSTOM_DISABLED;
+    $edit['third_party_settings[per_user_block][visibility]'] = PER_USER_BLOCK_CUSTOM_DISABLED;
     $this->drupalPostForm($block_path, $edit, 'Save block');
 
     $block = Block::load($block->id());
-    $visibility = $block->getVisibility();
-    $this->assertTrue($visibility['per_user']['custom'] == PER_USER_BLOCK_CUSTOM_DISABLED, 'New value was customizable, hidden by default.');
+    $visibility = $block->getThirdPartySetting('per_user_block', 'visibility', PER_USER_BLOCK_CUSTOM_FIXED);
+    $this->assertTrue($visibility == PER_USER_BLOCK_CUSTOM_DISABLED, 'New value was customizable, hidden by default.');
 
     // Ensure the settings appear on the users page.
     $configuration = $block->getPlugin()->getConfiguration();
