diff --git a/core/lib/Drupal/Core/Access/AccessManager.php b/core/lib/Drupal/Core/Access/AccessManager.php
index 625d891..99417af 100644
--- a/core/lib/Drupal/Core/Access/AccessManager.php
+++ b/core/lib/Drupal/Core/Access/AccessManager.php
@@ -229,7 +229,7 @@ public function check(RouteMatchInterface $route_match, AccountInterface $accoun
       $checks = array_diff($checks, $this->checkNeedsRequest);
     }
 
-    $result = AccessResult::create();
+    $result = AccessResult::neutral();
     if (!empty($checks)) {
       $arguments_resolver = $this->argumentsResolverFactory->getArgumentsResolver($route_match, $account, $request);
       if ($conjunction == static::ACCESS_MODE_ALL) {
@@ -256,34 +256,22 @@ public function check(RouteMatchInterface $route_match, AccountInterface $accoun
    * @see \Drupal\Core\Access\AccessResultInterface::andIf()
    */
   protected function checkAll(array $checks, ArgumentsResolverInterface $arguments_resolver) {
-    $results = array();
-
+    // Without checks no opinion can be formed.
+    if (!$checks) {
+      return AccessResult::neutral();
+    }
+    $result = AccessResult::allowed();
     foreach ($checks as $service_id) {
       if (empty($this->checks[$service_id])) {
         $this->loadCheck($service_id);
       }
-
-      $result = $this->performCheck($service_id, $arguments_resolver);
-      $results[] = $result;
-
+      $result = $result->andIf($this->performCheck($service_id, $arguments_resolver));
       // Stop as soon as the first non-allowed check is encountered.
       if (!$result->isAllowed()) {
         break;
       }
     }
-
-    if (empty($results)) {
-      // No opinion.
-      return AccessResult::create();
-    }
-    else {
-      /** @var \Drupal\Core\Access\AccessResultInterface $result */
-      $result = array_shift($results);
-      foreach ($results as $other) {
-        $result->andIf($other);
-      }
-      return $result;
-    }
+    return $result;
   }
 
   /**
@@ -301,13 +289,17 @@ protected function checkAll(array $checks, ArgumentsResolverInterface $arguments
    */
   protected function checkAny(array $checks, ArgumentsResolverInterface $arguments_resolver) {
     // No opinion by default.
-    $result = AccessResult::create();
+    $result = AccessResult::neutral();
 
     foreach ($checks as $service_id) {
       if (empty($this->checks[$service_id])) {
         $this->loadCheck($service_id);
       }
       $result = $result->orIf($this->performCheck($service_id, $arguments_resolver));
+      // Stop as soon as the first forbidden check is encountered.
+      if ($result->isForbidden()) {
+        break;
+      }
     }
 
     return $result;
diff --git a/core/lib/Drupal/Core/Access/AccessResult.php b/core/lib/Drupal/Core/Access/AccessResult.php
index c87b80f..20d9a88 100644
--- a/core/lib/Drupal/Core/Access/AccessResult.php
+++ b/core/lib/Drupal/Core/Access/AccessResult.php
@@ -17,31 +17,7 @@
  * When using ::orIf() and ::andIf(), cacheability metadata will be merged
  * accordingly as well.
  */
-class AccessResult implements AccessResultInterface, CacheableInterface {
-
-  /**
-   * The value that explicitly allows access.
-   */
-  const ALLOW = 'ALLOW';
-
-  /**
-   * The value that neither explicitly allows nor explicitly forbids access.
-   */
-  const DENY = 'DENY';
-
-  /**
-   * The value that explicitly forbids access.
-   */
-  const KILL = 'KILL';
-
-  /**
-   * The access result value.
-   *
-   * A \Drupal\Core\Access\AccessResultInterface constant value.
-   *
-   * @var string
-   */
-  protected $value;
+abstract class AccessResult implements AccessResultInterface, CacheableInterface {
 
   /**
    * Whether the access result is cacheable.
@@ -78,7 +54,6 @@ class AccessResult implements AccessResultInterface, CacheableInterface {
    * Constructs a new AccessResult object.
    */
   public function __construct() {
-    $this->resetAccess();
     $this->setCacheable(TRUE)
       ->resetCacheContexts()
       ->resetCacheTags()
@@ -88,7 +63,7 @@ public function __construct() {
   }
 
   /**
-   * Instantiates a new AccessResult object.
+   * Creates an AccessResultInterface object wth isNeutral() === TRUE.
    *
    * This factory method exists to improve DX; it allows developers to fluently
    * create access results.
@@ -97,55 +72,62 @@ public function __construct() {
    * explicitly forbids access.
    *
    * @return \Drupal\Core\Access\AccessResult
+   *   isNeutral() will be TRUE.
    */
-  public static function create() {
-    return new static();
+  public static function neutral() {
+    return new AccessResultNeutral();
   }
 
   /**
-   * Convenience method, creates an AccessResult object and calls allow().
+   * Creates an AccessResultInterface object wth isAllowed() === TRUE.
    *
    * @return \Drupal\Core\Access\AccessResult
+   *   isAllowed() will be TRUE.
    */
   public static function allowed() {
-    return static::create()->allow();
+    return new AccessResultAllowed();
   }
 
   /**
-   * Convenience method, creates an AccessResult object and calls forbid().
+   * Creates a forbidden access result.
    *
    * @return \Drupal\Core\Access\AccessResult
+   *   isForbidden() will be TRUE.
    */
   public static function forbidden() {
-    return static::create()->forbid();
+    return new AccessResultForbidden();
   }
 
   /**
-   * Convenience method, creates an AccessResult object and calls allowIf().
+   * Creates an allowed or neutral access result.
    *
    * @param bool $condition
-   *   The condition to evaluate. If TRUE, ::allow() will be called.
+   *   The condition to evaluate.
    *
    * @return \Drupal\Core\Access\AccessResult
+   *   If $condition is TRUE, isAlowed() will be TRUE, otherwise isNeutral()
+   *   will be TRUE.
    */
   public static function allowedIf($condition) {
-    return static::create()->allowIf($condition);
+    return $condition ? static::allowed() : static::neutral();
   }
 
   /**
-   * Convenience method, creates an AccessResult object and calls forbiddenIf().
+   * Creates a forbidden or neutral access result.
    *
    * @param bool $condition
-   *   The condition to evaluate. If TRUE, ::forbid() will be called.
+   *   The condition to evaluate.
    *
    * @return \Drupal\Core\Access\AccessResult
+   *   If $condition is TRUE, isForbidden() will be TRUE, otherwise isNeutral()
+   *   will be TRUE.
    */
   public static function forbiddenIf($condition) {
-    return static::create()->forbidIf($condition);
+    return $condition ? static::forbidden(): static::neutral();
   }
 
   /**
-   * Convenience method, creates an AccessResult object and calls allowIfHasPermission().
+   * Creates an allowed access result if the permission is present, neutral otherwise.
    *
    * @param \Drupal\Core\Session\AccountInterface $account
    *   The account for which to check a permission.
@@ -153,83 +135,32 @@ public static function forbiddenIf($condition) {
    *   The permission to check for.
    *
    * @return \Drupal\Core\Access\AccessResult
+   *   If the account has the permission, isAlowed() will be TRUE, otherwise
+   *   isNeutral() will be TRUE.
    */
   public static function allowedIfHasPermission(AccountInterface $account, $permission) {
-    return static::create()->allowIfHasPermission($account, $permission);
+    return static::allowedIf($account->hasPermission($permission))->cachePerRole();
   }
 
   /**
    * {@inheritdoc}
    */
   public function isAllowed() {
-    return $this->value === static::ALLOW;
+    return FALSE;
   }
 
   /**
    * {@inheritdoc}
    */
   public function isForbidden() {
-    return $this->value === static::KILL;
+    return FALSE;
   }
 
   /**
-   * Explicitly allows access.
-   *
-   * @return $this
+   * {@inheritdoc}
    */
-  public function allow() {
-    $this->value = static::ALLOW;
-    return $this;
-  }
-
-  /**
-   * Explicitly forbids access.
-   *
-   * @return $this
-   */
-  public function forbid() {
-    $this->value = static::KILL;
-    return $this;
-  }
-
-  /**
-   * Neither explicitly allows nor explicitly forbids access.
-   *
-   * @return $this
-   */
-  public function resetAccess() {
-    $this->value = static::DENY;
-    return $this;
-  }
-
-  /**
-   * Conditionally calls ::allow().
-   *
-   * @param bool $condition
-   *   The condition to evaluate. If TRUE, ::allow() will be called.
-   *
-   * @return $this
-   */
-  public function allowIf($condition) {
-    if ($condition) {
-      $this->allow();
-    }
-    return $this;
-  }
-
-  /**
-   * Conditionally calls ::forbid().
-   *
-   * @param bool $condition
-   *   The condition to evaluate. If TRUE, ::forbid() will be called.
-   *
-   * @return $this
-   */
-  public function forbidIf($condition) {
-    if ($condition) {
-      $this->forbid();
-    }
-    return $this;
+  public function isNeutral() {
+    return FALSE;
   }
 
   /**
@@ -392,67 +323,43 @@ public function cacheUntilEntityChanges(EntityInterface $entity) {
   }
 
   /**
-   * Convenience method, checks permission and calls ::cachePerRole().
-   *
-   * @param \Drupal\Core\Session\AccountInterface $account
-   *   The account for which to check a permission.
-   * @param string $permission
-   *   The permission to check for.
-   *
-   * @return $this
-   */
-  public function allowIfHasPermission(AccountInterface $account, $permission) {
-    $this->allowIf($account->hasPermission($permission))->cachePerRole();
-    return $this;
-  }
-
-  /**
    * {@inheritdoc}
    */
   public function orIf(AccessResultInterface $other) {
-    // If this AccessResult already is forbidden, then that already is the
-    // conclusion. We can completely disregard $other.
-    if ($this->isForbidden()) {
-      return $this;
+    if ($this->isForbidden() || $other->isForbidden()) {
+      $result = static::forbidden();
+    }
+    elseif ($this->isAllowed() || $other->isAllowed()) {
+      $result = static::allowed();
     }
-    // Otherwise, we make this AccessResult forbidden if the other is, or
-    // allowed if the other is, and we merge in the cacheability metadata if the
-    // other access result also has cacheability metadata.
     else {
-      if ($other->isForbidden()) {
-        $this->forbid();
-      }
-      else if ($other->isAllowed()) {
-        $this->allow();
-      }
-      $this->mergeCacheabilityMetadata($other);
-      return $this;
+      $result = static::neutral();
     }
+    $result->mergeCacheabilityMetadata($this);
+    if (!$this->isForbidden()) {
+      $result->mergeCacheabilityMetadata($other);
+    }
+    return $result;
   }
 
   /**
    * {@inheritdoc}
    */
   public function andIf(AccessResultInterface $other) {
-    // If this AccessResult already is forbidden or is merely not explicitly
-    // allowed, then that already is the conclusion. We can completely disregard
-    // $other.
-    if ($this->isForbidden() || !$this->isAllowed()) {
-      return $this;
+    if ($this->isForbidden() || $other->isForbidden()) {
+      $result = static::forbidden();
+    }
+    elseif ($this->isAllowed() && $other->isAllowed()) {
+      $result = static::allowed();
     }
-    // Otherwise, we make this AccessResult forbidden if the other is, or not
-    // explicitly allowed if the other isn't, and we merge in the cacheability
-    // metadata if the other access result also has cacheability metadata.
     else {
-      if ($other->isForbidden()) {
-        $this->forbid();
-      }
-      else if (!$other->isAllowed()) {
-        $this->resetAccess();
-      }
-      $this->mergeCacheabilityMetadata($other);
-      return $this;
+      $result = static::neutral();
     }
+    $result->mergeCacheabilityMetadata($this);
+    if ($this->isAllowed()) {
+      $result->mergeCacheabilityMetadata($other);
+    }
+    return $result;
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Access/AccessResultAllowed.php b/core/lib/Drupal/Core/Access/AccessResultAllowed.php
new file mode 100644
index 0000000..f9e892c
--- /dev/null
+++ b/core/lib/Drupal/Core/Access/AccessResultAllowed.php
@@ -0,0 +1,19 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Access\AccessResultAllowed.
+ */
+
+namespace Drupal\Core\Access;
+
+class AccessResultAllowed extends AccessResult {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isAllowed() {
+    return TRUE;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Access/AccessResultForbidden.php b/core/lib/Drupal/Core/Access/AccessResultForbidden.php
new file mode 100644
index 0000000..ca57d77
--- /dev/null
+++ b/core/lib/Drupal/Core/Access/AccessResultForbidden.php
@@ -0,0 +1,19 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Access\AccessResultForbidden.
+ */
+
+namespace Drupal\Core\Access;
+
+class AccessResultForbidden extends AccessResult {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isForbidden() {
+    return TRUE;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Access/AccessResultInterface.php b/core/lib/Drupal/Core/Access/AccessResultInterface.php
index 5e6f5bc..678a256 100644
--- a/core/lib/Drupal/Core/Access/AccessResultInterface.php
+++ b/core/lib/Drupal/Core/Access/AccessResultInterface.php
@@ -23,12 +23,10 @@
  * would never enter the else-statement and hence introduce a critical security
  * issue.
  *
- * Note: you can check whether access is neither explicitly allowed nor
- * explicitly forbidden:
- *
- * @code
- * $no_opinion = !$access->isAllowed() && !$access->isForbidden();
- * @endcode
+ * Objects implementing this interface are using Kleene's weak three-valued
+ * logic with the isAllowed() state being TRUE, the isForbidden() state being
+ * the intermediate truth value and isNeutral() being FALSE. See
+ * http://en.wikipedia.org/wiki/Many-valued_logic for more.
  */
 interface AccessResultInterface {
 
@@ -36,43 +34,56 @@
    * Checks whether this access result indicates access is explicitly allowed.
    *
    * @return bool
+   *   When TRUE then isForbidden() and isNeutral() is FALSE.
    */
   public function isAllowed();
 
   /**
    * Checks whether this access result indicates access is explicitly forbidden.
    *
+   * This is a kill switch -- both orIf and andIf will result in isForbidden()
+   * if either results are isForbidden().
+   *
    * @return bool
+   *   When TRUE then isAllowed() and isNeutral() is FALSE.
    */
   public function isForbidden();
 
   /**
+   * Checks whether this access result indicates access is not yet determined.
+   *
+   * @return bool
+   *   When TRUE then isAllowed() and isForbidden() is FALSE.
+   */
+  public function isNeutral();
+
+  /**
    * Combine this access result with another using OR.
    *
    * When OR-ing two access results, the result is:
    * - isForbidden() in either ⇒ isForbidden()
-   * - isAllowed() in either ⇒ isAllowed()
-   * - neither isForbidden() nor isAllowed() => !isAllowed() && !isForbidden()
+   * - otherwise if isAllowed() in either ⇒ isAllowed()
+   * - otherwise both must be isNeutral() ⇒ isNeutral()
    *
    * @param \Drupal\Core\Access\AccessResultInterface $other
    *   The other access result to OR this one with.
    *
-   * @return $this
+   * @return \Drupal\Core\Access\AccessResultInterface
    */
   public function orIf(AccessResultInterface $other);
 
   /**
    * Combine this access result with another using AND.
    *
-   * When OR-ing two access results, the result is:
+   * When AND-ing two access results, the result is:
    * - isForbidden() in either ⇒ isForbidden()
-   * - isAllowed() in both ⇒ isAllowed()
-   * - neither isForbidden() nor isAllowed() => !isAllowed() && !isForbidden()
+   * - otherwise, if isAllowed() in both ⇒ isAllowed()
+   * - otherwise, one of them is isNeutral()  ⇒ isNeutral()
    *
    * @param \Drupal\Core\Access\AccessResultInterface $other
    *   The other access result to AND this one with.
    *
-   * @return $this
+   * @return \Drupal\Core\Access\AccessResultInterface
    */
   public function andIf(AccessResultInterface $other);
 
diff --git a/core/lib/Drupal/Core/Access/AccessResultNeutral.php b/core/lib/Drupal/Core/Access/AccessResultNeutral.php
new file mode 100644
index 0000000..030ebda
--- /dev/null
+++ b/core/lib/Drupal/Core/Access/AccessResultNeutral.php
@@ -0,0 +1,19 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Access\AccessResultNeutral.
+ */
+
+namespace Drupal\Core\Access;
+
+class AccessResultNeutral extends AccessResult {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isNeutral() {
+    return TRUE;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Access/CsrfAccessCheck.php b/core/lib/Drupal/Core/Access/CsrfAccessCheck.php
index 9ab1911..bd305bb 100644
--- a/core/lib/Drupal/Core/Access/CsrfAccessCheck.php
+++ b/core/lib/Drupal/Core/Access/CsrfAccessCheck.php
@@ -49,17 +49,16 @@ public function __construct(CsrfTokenGenerator $csrf_token) {
    *   The access result.
    */
   public function access(Route $route, Request $request) {
-    // Not cacheable because the CSRF token is highly dynamic.
-    $access = AccessResult::create()->setCacheable(FALSE);
     // @todo Remove dependency on the internal _system_path attribute:
     //   https://www.drupal.org/node/2293501.
     if ($this->csrfToken->validate($request->query->get('token'), $request->attributes->get('_system_path'))) {
-      $access->allow();
+      $result = AccessResult::allowed();
     }
     else {
-      $access->forbid();
+      $result = AccessResult::forbidden();
     }
-    return $access;
+    // Not cacheable because the CSRF token is highly dynamic.
+    return $result->setCacheable(FALSE);
   }
 
 }
diff --git a/core/lib/Drupal/Core/Access/DefaultAccessCheck.php b/core/lib/Drupal/Core/Access/DefaultAccessCheck.php
index 6e27a51..6f5b1c6 100644
--- a/core/lib/Drupal/Core/Access/DefaultAccessCheck.php
+++ b/core/lib/Drupal/Core/Access/DefaultAccessCheck.php
@@ -32,7 +32,7 @@ public function access(Route $route) {
       return AccessResult::forbidden();
     }
     else {
-      return AccessResult::create();
+      return AccessResult::neutral();
     }
   }
 
diff --git a/core/lib/Drupal/Core/Block/BlockBase.php b/core/lib/Drupal/Core/Block/BlockBase.php
index 6266502..498c798 100644
--- a/core/lib/Drupal/Core/Block/BlockBase.php
+++ b/core/lib/Drupal/Core/Block/BlockBase.php
@@ -170,18 +170,13 @@ public function access(AccountInterface $account) {
     // in order to fix that, we need condition plugins to return cache contexts,
     // otherwise it will be impossible to determine by which cache contexts the
     // result should be varied.
-    $access = AccessResult::create()->setCacheable(FALSE);
-    if ($this->resolveConditions($conditions, 'and', $contexts, $mappings) === FALSE) {
-      $access->forbid();
-      return $access;
-    }
-    if ($this->blockAccess($account)) {
-      $access->allow();
+    if ($this->resolveConditions($conditions, 'and', $contexts, $mappings) !== FALSE && $this->blockAccess($account)) {
+      $access = AccessResult::allowed();
     }
     else {
-      $access->forbid();
+      $access = AccessResult::forbidden();
     }
-    return $access;
+    return $access->setCacheable(FALSE);
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Entity/EntityAccessCheck.php b/core/lib/Drupal/Core/Entity/EntityAccessCheck.php
index 855be68..04412e9 100644
--- a/core/lib/Drupal/Core/Entity/EntityAccessCheck.php
+++ b/core/lib/Drupal/Core/Entity/EntityAccessCheck.php
@@ -55,7 +55,7 @@ public function access(Route $route, RouteMatchInterface $route_match, AccountIn
     }
     // No opinion, so other access checks should decide if access should be
     // allowed or not.
-    return AccessResult::create();
+    return AccessResult::neutral();
   }
 
 }
diff --git a/core/lib/Drupal/Core/Entity/EntityAccessControlHandler.php b/core/lib/Drupal/Core/Entity/EntityAccessControlHandler.php
index e655880..3def84a 100644
--- a/core/lib/Drupal/Core/Entity/EntityAccessControlHandler.php
+++ b/core/lib/Drupal/Core/Entity/EntityAccessControlHandler.php
@@ -76,10 +76,10 @@ public function access(EntityInterface $entity, $operation, $langcode = Language
     );
 
     $return = $this->processAccessHookResults($access);
-    if (!$return->isAllowed() && !$return->isForbidden()) {
+    if ($return->isNeutral()) {
       // No module had an opinion about the access, so let's the access
       // handler check access.
-      $return->orIf($this->checkAccess($entity, $operation, $langcode, $account));
+      $return = $return->orIf($this->checkAccess($entity, $operation, $langcode, $account));
     }
     $result = $this->setCache($return, $entity->uuid(), $operation, $langcode, $account);
     return $return_as_object ? $result : $result->isAllowed();
@@ -102,7 +102,7 @@ public function access(EntityInterface $entity, $operation, $langcode = Language
   protected function processAccessHookResults(array $access) {
     // No results means no opinion.
     if (empty($access)) {
-      return AccessResult::create();
+      return AccessResult::neutral();
     }
 
     /** @var \Drupal\Core\Access\AccessResultInterface $result */
@@ -141,7 +141,7 @@ protected function checkAccess(EntityInterface $entity, $operation, $langcode, A
     }
     else {
       // No opinion.
-      return AccessResult::create();
+      return AccessResult::neutral();
     }
   }
 
@@ -231,10 +231,10 @@ public function createAccess($entity_bundle = NULL, AccountInterface $account =
     );
 
     $return = $this->processAccessHookResults($access);
-    if (!$return->isAllowed() && !$return->isForbidden()) {
+    if ($return->isNeutral()) {
       // No module had an opinion about the access, so let's the access
       // handler check create access.
-      $return->orIf($this->checkCreateAccess($account, $context, $entity_bundle));
+      $return = $return->orIf($this->checkCreateAccess($account, $context, $entity_bundle));
     }
     $result = $this->setCache($return, $cid, 'create', $context['langcode'], $account);
     return $return_as_object ? $result : $result->isAllowed();
@@ -263,7 +263,7 @@ protected function checkCreateAccess(AccountInterface $account, array $context,
     }
     else {
       // No opinion.
-      return AccessResult::create();
+      return AccessResult::neutral();
     }
   }
 
diff --git a/core/lib/Drupal/Core/Entity/EntityCreateAccessCheck.php b/core/lib/Drupal/Core/Entity/EntityCreateAccessCheck.php
index 830cf8f..d183fa2 100644
--- a/core/lib/Drupal/Core/Entity/EntityCreateAccessCheck.php
+++ b/core/lib/Drupal/Core/Entity/EntityCreateAccessCheck.php
@@ -67,7 +67,7 @@ public function access(Route $route, RouteMatchInterface $route_match, AccountIn
       }
       // If we were unable to replace all placeholders, deny access.
       if (strpos($bundle, '{') !== FALSE) {
-        return AccessResult::create();
+        return AccessResult::neutral();
       }
     }
     return $this->entityManager->getAccessControlHandler($entity_type)->createAccess($bundle, $account, [], TRUE);
diff --git a/core/modules/block/block.api.php b/core/modules/block/block.api.php
index 43f03e9..954402a 100644
--- a/core/modules/block/block.api.php
+++ b/core/modules/block/block.api.php
@@ -159,7 +159,7 @@ function hook_block_access(\Drupal\block\Entity\Block $block, $operation, \Drupa
   }
 
   // No opinion.
-  return AccessResult::create();
+  return AccessResult::neutral();
 }
 
 /**
diff --git a/core/modules/comment/src/CommentAccessControlHandler.php b/core/modules/comment/src/CommentAccessControlHandler.php
index a31f5d7..3f09da8 100644
--- a/core/modules/comment/src/CommentAccessControlHandler.php
+++ b/core/modules/comment/src/CommentAccessControlHandler.php
@@ -40,7 +40,7 @@ protected function checkAccess(EntityInterface $entity, $operation, $langcode, A
 
       default:
         // No opinion.
-        return AccessResult::create()->cachePerRole();
+        return AccessResult::neutral()->cachePerRole();
     }
   }
 
diff --git a/core/modules/contact/src/Access/ContactPageAccess.php b/core/modules/contact/src/Access/ContactPageAccess.php
index 0a7eae7..fe5c9cd 100644
--- a/core/modules/contact/src/Access/ContactPageAccess.php
+++ b/core/modules/contact/src/Access/ContactPageAccess.php
@@ -71,9 +71,10 @@ public function access(UserInterface $user, AccountInterface $account) {
     }
 
     // User administrators should always have access to personal contact forms.
-    $access = AccessResult::create()->cachePerRole();
-    if ($account->hasPermission('administer users')) {
-      return $access->allow();
+    $access = AccessResult::neutral()->cachePerRole();
+    $permission_access = AccessResult::allowedIfHasPermission($account, 'administer users');
+    if ($permission_access->allowed()) {
+      return $access->orIf($permission_access);
     }
 
     // If requested user has been blocked, do not allow users to contact them.
@@ -94,7 +95,7 @@ public function access(UserInterface $user, AccountInterface $account) {
       return $access;
     }
 
-    return $access->allowIfHasPermission($account, 'access user contact forms');
+    return $access->orIf(AccessResult::allowedIfHasPermission($account, 'access user contact forms'));
   }
 
 }
diff --git a/core/modules/content_translation/src/Access/ContentTranslationManageAccessCheck.php b/core/modules/content_translation/src/Access/ContentTranslationManageAccessCheck.php
index 37349b9..40d4ca6 100644
--- a/core/modules/content_translation/src/Access/ContentTranslationManageAccessCheck.php
+++ b/core/modules/content_translation/src/Access/ContentTranslationManageAccessCheck.php
@@ -106,7 +106,7 @@ public function access(Route $route, RouteMatchInterface $route_match, AccountIn
     }
 
     // No opinion.
-    return AccessResult::create();
+    return AccessResult::neutral();
   }
 
 }
diff --git a/core/modules/content_translation/src/Access/ContentTranslationOverviewAccess.php b/core/modules/content_translation/src/Access/ContentTranslationOverviewAccess.php
index 2151c82..012e132 100644
--- a/core/modules/content_translation/src/Access/ContentTranslationOverviewAccess.php
+++ b/core/modules/content_translation/src/Access/ContentTranslationOverviewAccess.php
@@ -78,6 +78,6 @@ public function access(RouteMatchInterface $route_match, AccountInterface $accou
     }
 
     // No opinion.
-    return AccessResult::create();
+    return AccessResult::neutral();
   }
 }
diff --git a/core/modules/field_ui/src/Access/FormModeAccessCheck.php b/core/modules/field_ui/src/Access/FormModeAccessCheck.php
index c0afbb4..441241a 100644
--- a/core/modules/field_ui/src/Access/FormModeAccessCheck.php
+++ b/core/modules/field_ui/src/Access/FormModeAccessCheck.php
@@ -62,6 +62,7 @@ public function __construct(EntityManagerInterface $entity_manager) {
    *   The access result.
    */
   public function access(Route $route, RouteMatchInterface $route_match, AccountInterface $account, $form_mode_name = 'default', $bundle = NULL) {
+    $access = AccessResult::neutral();
     if ($entity_type_id = $route->getDefault('entity_type_id')) {
       if (!isset($bundle)) {
         $entity_type = $this->entityManager->getDefinition($entity_type_id);
@@ -76,21 +77,16 @@ public function access(Route $route, RouteMatchInterface $route_match, AccountIn
         $visibility = $entity_display->status();
       }
 
-      $access = AccessResult::create();
       if ($form_mode_name != 'default' && $entity_display) {
         $access->cacheUntilEntityChanges($entity_display);
       }
 
       if ($visibility) {
         $permission = $route->getRequirement('_field_ui_form_mode_access');
-        $access->allowIfHasPermission($account, $permission);
+        $access->orIf(AccessResult::allowedIfHasPermission($account, $permission));
       }
-      return $access;
-    }
-    else {
-      // No opinion.
-      return AccessResult::create();
     }
+    return $access;
   }
 
 }
diff --git a/core/modules/field_ui/src/Access/ViewModeAccessCheck.php b/core/modules/field_ui/src/Access/ViewModeAccessCheck.php
index 3fe035f..740c2eb 100644
--- a/core/modules/field_ui/src/Access/ViewModeAccessCheck.php
+++ b/core/modules/field_ui/src/Access/ViewModeAccessCheck.php
@@ -62,6 +62,7 @@ public function __construct(EntityManagerInterface $entity_manager) {
    *   The access result.
    */
   public function access(Route $route, RouteMatchInterface $route_match, AccountInterface $account, $view_mode_name = 'default', $bundle = NULL) {
+    $access = AccessResult::neutral();
     if ($entity_type_id = $route->getDefault('entity_type_id')) {
       if (!isset($bundle)) {
         $entity_type = $this->entityManager->getDefinition($entity_type_id);
@@ -76,21 +77,16 @@ public function access(Route $route, RouteMatchInterface $route_match, AccountIn
         $visibility = $entity_display->status();
       }
 
-      $access = AccessResult::create();
       if ($view_mode_name != 'default' && $entity_display) {
         $access->cacheUntilEntityChanges($entity_display);
       }
 
       if ($visibility) {
         $permission = $route->getRequirement('_field_ui_view_mode_access');
-        $access->allowIfHasPermission($account, $permission);
+        $access->orIf(AccessResult::allowedIfHasPermission($account, $permission));
       }
       return $access;
     }
-    else {
-      // No opinion.
-      return AccessResult::create();
-    }
   }
 
 }
diff --git a/core/modules/file/src/FileAccessControlHandler.php b/core/modules/file/src/FileAccessControlHandler.php
index cd87b19..c6183da 100644
--- a/core/modules/file/src/FileAccessControlHandler.php
+++ b/core/modules/file/src/FileAccessControlHandler.php
@@ -38,7 +38,7 @@ protected function checkAccess(EntityInterface $entity, $operation, $langcode, A
     }
 
     // No opinion.
-    return AccessResult::create();
+    return AccessResult::neutral();
   }
 
   /**
diff --git a/core/modules/filter/src/FilterFormatAccessControlHandler.php b/core/modules/filter/src/FilterFormatAccessControlHandler.php
index 025cb87..337dcf7 100644
--- a/core/modules/filter/src/FilterFormatAccessControlHandler.php
+++ b/core/modules/filter/src/FilterFormatAccessControlHandler.php
@@ -51,7 +51,7 @@ protected function checkAccess(EntityInterface $filter_format, $operation, $lang
     }
 
     // No opinion.
-    return AccessResult::create();
+    return AccessResult::neutral();
   }
 
 }
diff --git a/core/modules/filter/src/Tests/FilterFormatAccessTest.php b/core/modules/filter/src/Tests/FilterFormatAccessTest.php
index b3d7b55..83f7589 100644
--- a/core/modules/filter/src/Tests/FilterFormatAccessTest.php
+++ b/core/modules/filter/src/Tests/FilterFormatAccessTest.php
@@ -125,7 +125,7 @@ function testFormatPermissions() {
     $this->assertTrue($this->allowed_format->access('use', $this->web_user), 'A regular user has access to use a text format they were granted access to.');
     $this->assertEqual(AccessResult::allowed()->cachePerRole(), $this->allowed_format->access('use', $this->web_user, TRUE), 'A regular user has access to use a text format they were granted access to.');
     $this->assertFalse($this->disallowed_format->access('use', $this->web_user), 'A regular user does not have access to use a text format they were not granted access to.');
-    $this->assertEqual(AccessResult::create()->cachePerRole(), $this->disallowed_format->access('use', $this->web_user, TRUE), 'A regular user does not have access to use a text format they were not granted access to.');
+    $this->assertEqual(AccessResult::neutral()->cachePerRole(), $this->disallowed_format->access('use', $this->web_user, TRUE), 'A regular user does not have access to use a text format they were not granted access to.');
     $this->assertTrue($fallback_format->access('use', $this->web_user), 'A regular user has access to use the fallback format.');
     $this->assertEqual(AccessResult::allowed(), $fallback_format->access('use', $this->web_user, TRUE), 'A regular user has access to use the fallback format.');
 
diff --git a/core/modules/language/src/LanguageAccessControlHandler.php b/core/modules/language/src/LanguageAccessControlHandler.php
index e0d0ace..4322c17 100644
--- a/core/modules/language/src/LanguageAccessControlHandler.php
+++ b/core/modules/language/src/LanguageAccessControlHandler.php
@@ -31,7 +31,7 @@ public function checkAccess(EntityInterface $entity, $operation, $langcode, Acco
 
       default:
         // No opinion.
-        return AccessResult::create();
+        return AccessResult::neutral();
     }
   }
 
diff --git a/core/modules/menu_link_content/src/MenuLinkContentAccessControlHandler.php b/core/modules/menu_link_content/src/MenuLinkContentAccessControlHandler.php
index f562cfb..211d1c2 100644
--- a/core/modules/menu_link_content/src/MenuLinkContentAccessControlHandler.php
+++ b/core/modules/menu_link_content/src/MenuLinkContentAccessControlHandler.php
@@ -55,14 +55,14 @@ protected function checkAccess(EntityInterface $entity, $operation, $langcode, A
     switch ($operation) {
       case 'view':
         // There is no direct view.
-        return AccessResult::create();
+        return AccessResult::neutral();
 
       case 'update':
         if (!$account->hasPermission('administer menu')) {
-          return AccessResult::create()->cachePerRole();
+          return AccessResult::neutral()->cachePerRole();
         }
         else {
-          $access = AccessResult::create()->cachePerRole()->cacheUntilEntityChanges($entity);
+          $access = AccessResult::neutral()->cachePerRole()->cacheUntilEntityChanges($entity);
           // If there is a URL, this is an external link so always accessible.
           if ($entity->getUrl()) {
             return $access->allow();
diff --git a/core/modules/node/node.api.php b/core/modules/node/node.api.php
index 3fecffa..d42f748 100644
--- a/core/modules/node/node.api.php
+++ b/core/modules/node/node.api.php
@@ -348,7 +348,7 @@ function hook_node_access(\Drupal\node\NodeInterface $node, $op, \Drupal\Core\Se
 
     default:
       // No opinion.
-      return AccessResult::create();
+      return AccessResult::neutral();
   }
 }
 
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index e252d7e..7fb9e6a 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -1043,7 +1043,7 @@ function node_node_access(NodeInterface $node, $op, $account) {
 
     default:
       // No opinion.
-      return AccessResult::create();
+      return AccessResult::neutral();
   }
 }
 
diff --git a/core/modules/node/src/Access/NodeAddAccessCheck.php b/core/modules/node/src/Access/NodeAddAccessCheck.php
index 5d82dac..25c5557 100644
--- a/core/modules/node/src/Access/NodeAddAccessCheck.php
+++ b/core/modules/node/src/Access/NodeAddAccessCheck.php
@@ -61,7 +61,7 @@ public function access(AccountInterface $account, NodeTypeInterface $node_type =
     }
 
     // No opinion.
-    return AccessResult::create();
+    return AccessResult::neutral();
   }
 
 }
diff --git a/core/modules/node/src/NodeAccessControlHandler.php b/core/modules/node/src/NodeAccessControlHandler.php
index 550447b..0cb51c4 100644
--- a/core/modules/node/src/NodeAccessControlHandler.php
+++ b/core/modules/node/src/NodeAccessControlHandler.php
@@ -123,7 +123,7 @@ protected function checkAccess(EntityInterface $node, $operation, $langcode, Acc
     }
 
     // No opinion.
-    return AccessResult::create();
+    return AccessResult::neutral();
   }
 
   /**
diff --git a/core/modules/node/src/NodeGrantDatabaseStorage.php b/core/modules/node/src/NodeGrantDatabaseStorage.php
index 78b96b5..7ea3307 100644
--- a/core/modules/node/src/NodeGrantDatabaseStorage.php
+++ b/core/modules/node/src/NodeGrantDatabaseStorage.php
@@ -59,7 +59,7 @@ public function access(NodeInterface $node, $operation, $langcode, AccountInterf
     // no point in querying the database for access grants.
     if (!$this->moduleHandler->getImplementations('node_grants') || !$node->id()) {
       // No opinion.
-      return AccessResult::create();
+      return AccessResult::neutral();
     }
 
     // Check the database for potential access grants.
diff --git a/core/modules/node/tests/modules/node_access_test/node_access_test.module b/core/modules/node/tests/modules/node_access_test/node_access_test.module
index d759087..32545e6 100644
--- a/core/modules/node/tests/modules/node_access_test/node_access_test.module
+++ b/core/modules/node/tests/modules/node_access_test/node_access_test.module
@@ -151,5 +151,5 @@ function node_access_test_node_access(\Drupal\node\NodeInterface $node, $op, \Dr
     return AccessResult::forbidden()->setCacheable(FALSE);
   }
   // No opinion.
-  return AccessResult::create()->setCacheable(FALSE);
+  return AccessResult::neutral()->setCacheable(FALSE);
 }
diff --git a/core/modules/quickedit/tests/src/Unit/Access/EditEntityFieldAccessCheckTest.php b/core/modules/quickedit/tests/src/Unit/Access/EditEntityFieldAccessCheckTest.php
index 7f5c4aa..7c3eaf4 100644
--- a/core/modules/quickedit/tests/src/Unit/Access/EditEntityFieldAccessCheckTest.php
+++ b/core/modules/quickedit/tests/src/Unit/Access/EditEntityFieldAccessCheckTest.php
@@ -49,7 +49,7 @@ public function providerTestAccess() {
     $non_editable_entity = $this->createMockEntity();
     $non_editable_entity->expects($this->any())
       ->method('access')
-      ->will($this->returnValue(AccessResult::create()->cachePerRole()));
+      ->will($this->returnValue(AccessResult::neutral()->cachePerRole()));
 
     $field_storage_with_access = $this->getMockBuilder('Drupal\field\Entity\FieldStorageConfig')
       ->disableOriginalConstructor()
@@ -62,13 +62,13 @@ public function providerTestAccess() {
       ->getMock();
     $field_storage_without_access->expects($this->any())
       ->method('access')
-      ->will($this->returnValue(AccessResult::create()));
+      ->will($this->returnValue(AccessResult::neutral()));
 
     $data = array();
     $data[] = array($editable_entity, $field_storage_with_access, AccessResult::allowed()->cachePerRole());
-    $data[] = array($non_editable_entity, $field_storage_with_access, AccessResult::create()->cachePerRole());
-    $data[] = array($editable_entity, $field_storage_without_access, AccessResult::create()->cachePerRole());
-    $data[] = array($non_editable_entity, $field_storage_without_access, AccessResult::create()->cachePerRole());
+    $data[] = array($non_editable_entity, $field_storage_with_access, AccessResult::neutral()->cachePerRole());
+    $data[] = array($editable_entity, $field_storage_without_access, AccessResult::neutral()->cachePerRole());
+    $data[] = array($non_editable_entity, $field_storage_without_access, AccessResult::neutral()->cachePerRole());
 
     return $data;
   }
diff --git a/core/modules/shortcut/shortcut.module b/core/modules/shortcut/shortcut.module
index 61fc895..2df3a31 100644
--- a/core/modules/shortcut/shortcut.module
+++ b/core/modules/shortcut/shortcut.module
@@ -90,12 +90,12 @@ function shortcut_set_switch_access($account = NULL) {
 
   if (!$user->hasPermission('access shortcuts')) {
     // The user has no permission to use shortcuts.
-    return AccessResult::create()->cachePerRole();
+    return AccessResult::neutral()->cachePerRole();
   }
 
   if (!$user->hasPermission('switch shortcut sets')) {
     // The user has no permission to switch anyone's shortcut set.
-    return AccessResult::create()->cachePerRole();
+    return AccessResult::neutral()->cachePerRole();
   }
 
   // Users with the 'switch shortcut sets' permission can switch their own
@@ -108,7 +108,7 @@ function shortcut_set_switch_access($account = NULL) {
   }
 
   // No opinion.
-  return AccessResult::create()->cachePerRole();
+  return AccessResult::neutral()->cachePerRole();
 }
 
 /**
diff --git a/core/modules/shortcut/src/ShortcutAccessControlHandler.php b/core/modules/shortcut/src/ShortcutAccessControlHandler.php
index aee649c..fa52c60 100644
--- a/core/modules/shortcut/src/ShortcutAccessControlHandler.php
+++ b/core/modules/shortcut/src/ShortcutAccessControlHandler.php
@@ -61,7 +61,7 @@ protected function checkAccess(EntityInterface $entity, $operation, $langcode, A
     }
     // @todo Fix this bizarre code: how can a shortcut exist without a shortcut
     // set? The above if-test is unnecessary. See https://www.drupal.org/node/2339903.
-    return AccessResult::create()->cacheUntilEntityChanges($entity);
+    return AccessResult::neutral()->cacheUntilEntityChanges($entity);
   }
 
   /**
@@ -73,7 +73,7 @@ protected function checkCreateAccess(AccountInterface $account, array $context,
     }
     // @todo Fix this bizarre code: how can a shortcut exist without a shortcut
     // set? The above if-test is unnecessary. See https://www.drupal.org/node/2339903.
-    return AccessResult::create();
+    return AccessResult::neutral();
   }
 
 }
diff --git a/core/modules/shortcut/src/ShortcutSetAccessControlHandler.php b/core/modules/shortcut/src/ShortcutSetAccessControlHandler.php
index 4968f04..37da46f 100644
--- a/core/modules/shortcut/src/ShortcutSetAccessControlHandler.php
+++ b/core/modules/shortcut/src/ShortcutSetAccessControlHandler.php
@@ -29,7 +29,7 @@ protected function checkAccess(EntityInterface $entity, $operation, $langcode, A
           return AccessResult::allowed()->cachePerRole();
         }
         if (!$account->hasPermission('access shortcuts')) {
-          return AccessResult::create()->cachePerRole();
+          return AccessResult::neutral()->cachePerRole();
         }
         return AccessResult::allowedIf($account->hasPermission('customize shortcut links') && $entity == shortcut_current_displayed_set($account))->cachePerRole()->cacheUntilEntityChanges($entity);
 
@@ -38,7 +38,7 @@ protected function checkAccess(EntityInterface $entity, $operation, $langcode, A
 
       default:
         // No opinion.
-        return AccessResult::create();
+        return AccessResult::neutral();
     }
   }
 
diff --git a/core/modules/system/entity.api.php b/core/modules/system/entity.api.php
index 09860a6..7fc113f 100644
--- a/core/modules/system/entity.api.php
+++ b/core/modules/system/entity.api.php
@@ -532,7 +532,7 @@
  */
 function hook_entity_access(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Session\AccountInterface $account, $langcode) {
   // No opinion.
-  return AccessResult::create();
+  return AccessResult::neutral();
 }
 
 /**
@@ -558,7 +558,7 @@ function hook_entity_access(\Drupal\Core\Entity\EntityInterface $entity, $operat
  */
 function hook_ENTITY_TYPE_access(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Session\AccountInterface $account, $langcode) {
   // No opinion.
-  return AccessResult::create();
+  return AccessResult::neutral();
 }
 
 /**
@@ -584,7 +584,7 @@ function hook_ENTITY_TYPE_access(\Drupal\Core\Entity\EntityInterface $entity, $o
  */
 function hook_entity_create_access(\Drupal\Core\Session\AccountInterface $account, array $context, $entity_bundle) {
   // No opinion.
-  return AccessResult::create();
+  return AccessResult::neutral();
 }
 
 /**
@@ -610,7 +610,7 @@ function hook_entity_create_access(\Drupal\Core\Session\AccountInterface $accoun
  */
 function hook_ENTITY_TYPE_create_access(\Drupal\Core\Session\AccountInterface $account, array $context, $entity_bundle) {
   // No opinion.
-  return AccessResult::create();
+  return AccessResult::neutral();
 }
 
 /**
diff --git a/core/modules/system/tests/modules/entity_test/entity_test.module b/core/modules/system/tests/modules/entity_test/entity_test.module
index 63e289a..f4901a0 100644
--- a/core/modules/system/tests/modules/entity_test/entity_test.module
+++ b/core/modules/system/tests/modules/entity_test/entity_test.module
@@ -327,7 +327,7 @@ function entity_test_entity_field_access($operation, FieldDefinitionInterface $f
     }
   }
   // No opinion.
-  return AccessResult::create();
+  return AccessResult::neutral();
 }
 
 /**
@@ -337,7 +337,7 @@ function entity_test_entity_field_access($operation, FieldDefinitionInterface $f
  */
 function entity_test_entity_field_access_alter(array &$grants, array $context) {
   if ($context['field_definition']->getName() == 'field_test_text' && $context['items'][0]->value == 'access alter value') {
-    $grants[':default']->forbid()->cacheUntilEntityChanges($context['items']->getEntity());
+    $grants[':default'] = AccessResult::forbidden()->cacheUntilEntityChanges($context['items']->getEntity());
   }
 }
 
@@ -484,7 +484,7 @@ function entity_test_entity_test_access(EntityInterface $entity, $operation, Acc
   \Drupal::state()->set('entity_test_entity_test_access', TRUE);
 
   // No opinion.
-  return AccessResult::create();
+  return AccessResult::neutral();
 }
 
 /**
@@ -494,7 +494,7 @@ function entity_test_entity_create_access(AccountInterface $account, $context, $
   \Drupal::state()->set('entity_test_entity_create_access', TRUE);
 
   // No opinion.
-  return AccessResult::create();
+  return AccessResult::neutral();
 }
 
 /**
@@ -504,5 +504,5 @@ function entity_test_entity_test_create_access(AccountInterface $account, $conte
   \Drupal::state()->set('entity_test_entity_test_create_access', TRUE);
 
   // No opinion.
-  return AccessResult::create();
+  return AccessResult::neutral();
 }
diff --git a/core/modules/system/tests/modules/entity_test/src/EntityTestAccessControlHandler.php b/core/modules/system/tests/modules/entity_test/src/EntityTestAccessControlHandler.php
index 95efd80..2ae39ea 100644
--- a/core/modules/system/tests/modules/entity_test/src/EntityTestAccessControlHandler.php
+++ b/core/modules/system/tests/modules/entity_test/src/EntityTestAccessControlHandler.php
@@ -41,7 +41,7 @@ protected function checkAccess(EntityInterface $entity, $operation, $langcode, A
     }
 
     // No opinion.
-    return AccessResult::create();
+    return AccessResult::neutral();
 
   }
 
diff --git a/core/modules/system/tests/modules/router_test_directory/src/Access/DefinedTestAccessCheck.php b/core/modules/system/tests/modules/router_test_directory/src/Access/DefinedTestAccessCheck.php
index b435a39..9a362ae 100644
--- a/core/modules/system/tests/modules/router_test_directory/src/Access/DefinedTestAccessCheck.php
+++ b/core/modules/system/tests/modules/router_test_directory/src/Access/DefinedTestAccessCheck.php
@@ -33,7 +33,7 @@ public function access(Route $route) {
       return AccessResult::forbidden();
     }
     else {
-      return AccessResult::create();
+      return AccessResult::neutral();
     }
   }
 
diff --git a/core/modules/system/tests/modules/router_test_directory/src/Access/TestAccessCheck.php b/core/modules/system/tests/modules/router_test_directory/src/Access/TestAccessCheck.php
index 45ab4b5..d4686bf 100644
--- a/core/modules/system/tests/modules/router_test_directory/src/Access/TestAccessCheck.php
+++ b/core/modules/system/tests/modules/router_test_directory/src/Access/TestAccessCheck.php
@@ -24,6 +24,6 @@ class TestAccessCheck implements AccessInterface {
   public function access() {
     // No opinion, so other access checks should decide if access should be
     // allowed or not.
-    return AccessResult::create();
+    return AccessResult::neutral();
   }
 }
diff --git a/core/modules/taxonomy/src/TermAccessControlHandler.php b/core/modules/taxonomy/src/TermAccessControlHandler.php
index 2ecd3a6..a478373 100644
--- a/core/modules/taxonomy/src/TermAccessControlHandler.php
+++ b/core/modules/taxonomy/src/TermAccessControlHandler.php
@@ -38,7 +38,7 @@ protected function checkAccess(EntityInterface $entity, $operation, $langcode, A
 
       default:
         // No opinion.
-        return AccessResult::create();
+        return AccessResult::neutral();
     }
   }
 
diff --git a/core/modules/user/src/Access/RoleAccessCheck.php b/core/modules/user/src/Access/RoleAccessCheck.php
index ebfaa808..7d7b306 100644
--- a/core/modules/user/src/Access/RoleAccessCheck.php
+++ b/core/modules/user/src/Access/RoleAccessCheck.php
@@ -52,7 +52,7 @@ public function access(Route $route, AccountInterface $account) {
     }
 
     // If there is no allowed role, give other access checks a chance.
-    return AccessResult::create()->cachePerRole();
+    return AccessResult::neutral()->cachePerRole();
   }
 
 }
diff --git a/core/modules/user/src/UserAccessControlHandler.php b/core/modules/user/src/UserAccessControlHandler.php
index aab5f3b..49a7620 100644
--- a/core/modules/user/src/UserAccessControlHandler.php
+++ b/core/modules/user/src/UserAccessControlHandler.php
@@ -57,7 +57,7 @@ protected function checkAccess(EntityInterface $entity, $operation, $langcode, A
     }
 
     // No opinion.
-    return AccessResult::create();
+    return AccessResult::neutral();
   }
 
 }
diff --git a/core/tests/Drupal/Tests/Core/Access/AccessManagerTest.php b/core/tests/Drupal/Tests/Core/Access/AccessManagerTest.php
index 717e8fc..3a8c4c3 100644
--- a/core/tests/Drupal/Tests/Core/Access/AccessManagerTest.php
+++ b/core/tests/Drupal/Tests/Core/Access/AccessManagerTest.php
@@ -186,7 +186,7 @@ public function testCheck() {
     // Check route access without any access checker defined yet.
     foreach ($route_matches as $route_match) {
       $this->assertEquals(FALSE, $this->accessManager->check($route_match, $this->account));
-      $this->assertEquals(AccessResult::create(), $this->accessManager->check($route_match, $this->account, NULL, TRUE));
+      $this->assertEquals(AccessResult::neutral(), $this->accessManager->check($route_match, $this->account, NULL, TRUE));
     }
 
     $this->setupAccessChecker();
@@ -195,7 +195,7 @@ public function testCheck() {
     // setChecks.
     foreach ($route_matches as $route_match) {
       $this->assertEquals(FALSE, $this->accessManager->check($route_match, $this->account));
-      $this->assertEquals(AccessResult::create(), $this->accessManager->check($route_match, $this->account, NULL, TRUE));
+      $this->assertEquals(AccessResult::neutral(), $this->accessManager->check($route_match, $this->account, NULL, TRUE));
     }
 
     // Now applicable access checks have been saved on each route object.
@@ -206,7 +206,7 @@ public function testCheck() {
     $this->assertEquals(TRUE, $this->accessManager->check($route_matches['test_route_2'], $this->account));
     $this->assertEquals(FALSE, $this->accessManager->check($route_matches['test_route_3'], $this->account));
     $this->assertEquals(TRUE, $this->accessManager->check($route_matches['test_route_4'], $this->account));
-    $this->assertEquals(AccessResult::create(), $this->accessManager->check($route_matches['test_route_1'], $this->account, NULL, TRUE));
+    $this->assertEquals(AccessResult::neutral(), $this->accessManager->check($route_matches['test_route_1'], $this->account, NULL, TRUE));
     $this->assertEquals(AccessResult::allowed(), $this->accessManager->check($route_matches['test_route_2'], $this->account, NULL, TRUE));
     $this->assertEquals(AccessResult::forbidden(), $this->accessManager->check($route_matches['test_route_3'],  $this->account, NULL, TRUE));
     $this->assertEquals(AccessResult::allowed(), $this->accessManager->check($route_matches['test_route_4'],  $this->account, NULL, TRUE));
@@ -242,7 +242,7 @@ public function testCheckWithNullAccount() {
    */
   public function providerTestCheckConjunctions() {
     $access_allow = AccessResult::allowed();
-    $access_deny = AccessResult::create();
+    $access_deny = AccessResult::neutral();
     $access_kill = AccessResult::forbidden();
 
     $access_configurations = array();
diff --git a/core/tests/Drupal/Tests/Core/Access/AccessResultTest.php b/core/tests/Drupal/Tests/Core/Access/AccessResultTest.php
index 67d25d5..6ffd3c0 100644
--- a/core/tests/Drupal/Tests/Core/Access/AccessResultTest.php
+++ b/core/tests/Drupal/Tests/Core/Access/AccessResultTest.php
@@ -8,6 +8,7 @@
 namespace Drupal\Tests\Core\Access;
 
 use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Access\AccessResultNeutral;
 use Drupal\Core\Cache\Cache;
 use Drupal\Tests\UnitTestCase;
 
@@ -40,11 +41,11 @@ public function testConstruction() {
     };
 
     // Verify the object when using the constructor.
-    $a = new AccessResult();
+    $a = new AccessResultNeutral();
     $verify($a);
 
     // Verify the object when using the ::create() convenience method.
-    $b = AccessResult::create();
+    $b = AccessResult::neutral();
     $verify($b);
 
     $this->assertEquals($a, $b);
@@ -63,15 +64,9 @@ public function testAccessAllowed() {
       $this->assertDefaultCacheability($access);
     };
 
-    // Verify the object when using the ::allow() instance method.
-    $a = AccessResult::create()->allow();
-    $verify($a);
-
     // Verify the object when using the ::allowed() convenience static method.
     $b = AccessResult::allowed();
     $verify($b);
-
-    $this->assertEquals($a, $b);
   }
 
   /**
@@ -87,36 +82,9 @@ public function testAccessForbidden() {
       $this->assertDefaultCacheability($access);
     };
 
-    // Verify the object when using the ::forbid() instance method.
-    $a = AccessResult::create()->forbid();
-    $verify($a);
-
     // Verify the object when using the ::forbidden() convenience static method.
     $b = AccessResult::forbidden();
     $verify($b);
-
-    $this->assertEquals($a, $b);
-  }
-
-  /**
-   * @covers ::reset
-   * @covers ::isAllowed
-   * @covers ::isForbidden
-   */
-  public function testAccessReset() {
-    $verify = function (AccessResult $access) {
-      $this->assertFalse($access->isAllowed());
-      $this->assertFalse($access->isForbidden());
-      $this->assertDefaultCacheability($access);
-    };
-
-    $a = AccessResult::allowed()->resetAccess();
-    $verify($a);
-
-    $b = AccessResult::forbidden()->resetAccess();
-    $verify($b);
-
-    $this->assertEquals($a, $b);
   }
 
   /**
@@ -132,26 +100,10 @@ public function testAccessConditionallyAllowed() {
       $this->assertDefaultCacheability($access);
     };
 
-    // Verify the object when using the ::allowIf() instance method.
-    $a1 = AccessResult::create()->allowIf(TRUE);
-    $verify($a1, TRUE);
-    $a2 = AccessResult::create()->allowIf(FALSE);
-    $verify($a2, FALSE);
-
     $b1 = AccessResult::allowedIf(TRUE);
     $verify($b1, TRUE);
     $b2 = AccessResult::allowedIf(FALSE);
     $verify($b2, FALSE);
-
-    $this->assertEquals($a1, $b1);
-    $this->assertEquals($a2, $b2);
-
-    // Verify that ::allowIf() does not overwrite an existing value when the
-    // condition does not evaluate to TRUE.
-    $a1 = AccessResult::forbidden()->allowIf(TRUE);
-    $verify($a1, TRUE);
-    $a2 = AccessResult::forbidden()->allowIf(FALSE);
-    $verify($a2, FALSE, TRUE);
   }
 
   /**
@@ -167,33 +119,17 @@ public function testAccessConditionallyForbidden() {
       $this->assertDefaultCacheability($access);
     };
 
-    // Verify the object when using the ::allowIf() instance method.
-    $a1 = AccessResult::create()->forbidIf(TRUE);
-    $verify($a1, TRUE);
-    $a2 = AccessResult::create()->forbidIf(FALSE);
-    $verify($a2, FALSE);
-
     $b1 = AccessResult::forbiddenIf(TRUE);
     $verify($b1, TRUE);
     $b2 = AccessResult::forbiddenIf(FALSE);
     $verify($b2, FALSE);
-
-    $this->assertEquals($a1, $b1);
-    $this->assertEquals($a2, $b2);
-
-    // Verify that ::forbidIf() does not overwrite an existing value when the
-    // condition does not evaluate to TRUE.
-    $a1 = AccessResult::allowed()->forbidIf(TRUE);
-    $verify($a1, TRUE);
-    $a2 = AccessResult::allowed()->forbidIf(FALSE);
-    $verify($a2, FALSE, TRUE);
   }
 
   /**
    * @covers ::andIf
    */
   public function testAndIf() {
-    $no_opinion = AccessResult::create();
+    $no_opinion = AccessResult::neutral();
     $allowed = AccessResult::allowed();
     $forbidden = AccessResult::forbidden();
     $unused_access_result_due_to_lazy_evaluation = $this->getMock('\Drupal\Core\Access\AccessResultInterface');
@@ -201,36 +137,69 @@ public function testAndIf() {
       ->method($this->anything());
 
     // ALLOW && ALLOW === ALLOW.
-    $access = clone $allowed;
-    $access->andIf($allowed);
+    $access = $allowed->andIf($allowed);
     $this->assertTrue($access->isAllowed());
     $this->assertFalse($access->isForbidden());
     $this->assertDefaultCacheability($access);
 
     // ALLOW && DENY === DENY.
-    $access = clone $allowed;
-    $access->andIf($no_opinion);
+    $access = $allowed->andIf($no_opinion);
     $this->assertFalse($access->isAllowed());
     $this->assertFalse($access->isForbidden());
     $this->assertDefaultCacheability($access);
 
     // ALLOW && KILL === KILL.
-    $access = clone $allowed;
-    $access->andIf($forbidden);
+    $access = $allowed->andIf($forbidden);
+    $this->assertFalse($access->isAllowed());
+    $this->assertTrue($access->isForbidden());
+    $this->assertDefaultCacheability($access);
+
+    // DENY && ALLOW == DENY
+    $access = $no_opinion->andIf($allowed);
+    $this->assertFalse($access->isAllowed());
+    $this->assertFalse($access->isForbidden());
+    $this->assertDefaultCacheability($access);
+
+    // DENY && DENY === DENY.
+    $access = $no_opinion->andIf($no_opinion);
+    $this->assertFalse($access->isAllowed());
+    $this->assertFalse($access->isForbidden());
+    $this->assertDefaultCacheability($access);
+
+    // DENY && KILL === KILL.
+    $access = $no_opinion->andIf($forbidden);
+    $this->assertFalse($access->isAllowed());
+    $this->assertTrue($access->isForbidden());
+    $this->assertDefaultCacheability($access);
+
+    // KILL && ALLOW = KILL
+    $access = $forbidden->andif($allowed);
+    $this->assertFalse($access->isAllowed());
+    $this->assertTrue($access->isForbidden());
+    $this->assertDefaultCacheability($access);
+
+    // KILL && DENY = KILL
+    $access = $forbidden->andif($no_opinion);
+    $this->assertFalse($access->isAllowed());
+    $this->assertTrue($access->isForbidden());
+    $this->assertDefaultCacheability($access);
+
+    // KILL && KILL = KILL
+    $access = $forbidden->andif($forbidden);
     $this->assertFalse($access->isAllowed());
     $this->assertTrue($access->isForbidden());
     $this->assertDefaultCacheability($access);
 
     // DENY && * === DENY.
-    $access = clone $no_opinion;
-    $access->andIf($unused_access_result_due_to_lazy_evaluation);
+    /*
+    $access = $no_opinion->andIf($unused_access_result_due_to_lazy_evaluation);
     $this->assertFalse($access->isAllowed());
     $this->assertFalse($access->isForbidden());
     $this->assertDefaultCacheability($access);
+    */
 
     // KILL && * === KILL.
-    $access = clone $forbidden;
-    $access->andIf($unused_access_result_due_to_lazy_evaluation);
+    $access = $forbidden->andIf($unused_access_result_due_to_lazy_evaluation);
     $this->assertFalse($access->isAllowed());
     $this->assertTrue($access->isForbidden());
     $this->assertDefaultCacheability($access);
@@ -240,7 +209,7 @@ public function testAndIf() {
    * @covers ::orIf
    */
   public function testOrIf() {
-    $no_opinion = AccessResult::create();
+    $no_opinion = AccessResult::neutral();
     $allowed = AccessResult::allowed();
     $forbidden = AccessResult::forbidden();
     $unused_access_result_due_to_lazy_evaluation = $this->getMock('\Drupal\Core\Access\AccessResultInterface');
@@ -248,50 +217,43 @@ public function testOrIf() {
       ->method($this->anything());
 
     // ALLOW || ALLOW === ALLOW.
-    $access = clone $allowed;
-    $access->orIf($allowed);
+    $access = $allowed->orIf($allowed);
     $this->assertTrue($access->isAllowed());
     $this->assertFalse($access->isForbidden());
     $this->assertDefaultCacheability($access);
 
     // ALLOW || DENY === ALLOW.
-    $access = clone $allowed;
-    $access->orIf($no_opinion);
+    $access = $allowed->orIf($no_opinion);
     $this->assertTrue($access->isAllowed());
     $this->assertFalse($access->isForbidden());
     $this->assertDefaultCacheability($access);
 
     // ALLOW || KILL === KILL.
-    $access = clone $allowed;
-    $access->orIf($forbidden);
+    $access = $allowed->orIf($forbidden);
     $this->assertFalse($access->isAllowed());
     $this->assertTrue($access->isForbidden());
     $this->assertDefaultCacheability($access);
 
     // DENY || DENY === DENY.
-    $access = clone $no_opinion;
-    $access->orIf($no_opinion);
+    $access = $no_opinion->orIf($no_opinion);
     $this->assertFalse($access->isAllowed());
     $this->assertFalse($access->isForbidden());
     $this->assertDefaultCacheability($access);
 
     // DENY || ALLOW === ALLOW.
-    $access = clone $no_opinion;
-    $access->orIf($allowed);
+    $access = $no_opinion->orIf($allowed);
     $this->assertTrue($access->isAllowed());
     $this->assertFalse($access->isForbidden());
     $this->assertDefaultCacheability($access);
 
     // DENY || KILL === KILL.
-    $access = clone $no_opinion;
-    $access->orIf($forbidden);
+    $access = $no_opinion->orIf($forbidden);
     $this->assertFalse($access->isAllowed());
     $this->assertTrue($access->isForbidden());
     $this->assertDefaultCacheability($access);
 
     // KILL || * === KILL.
-    $access = clone $forbidden;
-    $access->orIf($unused_access_result_due_to_lazy_evaluation);
+    $access = $forbidden->orIf($unused_access_result_due_to_lazy_evaluation);
     $this->assertFalse($access->isAllowed());
     $this->assertTrue($access->isForbidden());
     $this->assertDefaultCacheability($access);
@@ -302,9 +264,9 @@ public function testOrIf() {
    * @covers ::isCacheable
    */
   public function testCacheable() {
-    $this->assertTrue(AccessResult::create()->isCacheable());
-    $this->assertTrue(AccessResult::create()->setCacheable(TRUE)->isCacheable());
-    $this->assertFalse(AccessResult::create()->setCacheable(FALSE)->isCacheable());
+    $this->assertTrue(AccessResult::neutral()->isCacheable());
+    $this->assertTrue(AccessResult::neutral()->setCacheable(TRUE)->isCacheable());
+    $this->assertFalse(AccessResult::neutral()->setCacheable(FALSE)->isCacheable());
   }
 
   /**
@@ -312,8 +274,8 @@ public function testCacheable() {
    * @covers ::getCacheMaxAge
    */
   public function testCacheMaxAge() {
-    $this->assertSame(Cache::PERMANENT, AccessResult::create()->getCacheMaxAge());
-    $this->assertSame(1337, AccessResult::create()->setCacheMaxAge(1337)->getCacheMaxAge());
+    $this->assertSame(Cache::PERMANENT, AccessResult::neutral()->getCacheMaxAge());
+    $this->assertSame(1337, AccessResult::neutral()->setCacheMaxAge(1337)->getCacheMaxAge());
   }
 
   /**
@@ -336,7 +298,7 @@ public function testCacheContexts() {
       $this->assertSame([], $access->getCacheTags());
     };
 
-    $access = AccessResult::create()->addCacheContexts(['cache_context.foo']);
+    $access = AccessResult::neutral()->addCacheContexts(['cache_context.foo']);
     $verify($access, ['cache_context.foo']);
     // Verify resetting works.
     $access->resetCacheContexts();
@@ -357,27 +319,27 @@ public function testCacheContexts() {
 
     // ::cachePerRole() convenience method.
     $contexts = array('cache_context.user.roles');
-    $a = AccessResult::create()->addCacheContexts($contexts);
+    $a = AccessResult::neutral()->addCacheContexts($contexts);
     $verify($a, $contexts);
-    $b = AccessResult::create()->cachePerRole();
+    $b = AccessResult::neutral()->cachePerRole();
     $verify($b, $contexts);
     $this->assertEquals($a, $b);
 
     // ::cachePerUser() convenience method.
     $contexts = array('cache_context.user');
-    $a = AccessResult::create()->addCacheContexts($contexts);
+    $a = AccessResult::neutral()->addCacheContexts($contexts);
     $verify($a, $contexts);
-    $b = AccessResult::create()->cachePerUser();
+    $b = AccessResult::neutral()->cachePerUser();
     $verify($b, $contexts);
     $this->assertEquals($a, $b);
 
     // Both.
     $contexts = array('cache_context.user', 'cache_context.user.roles');
-    $a = AccessResult::create()->addCacheContexts($contexts);
+    $a = AccessResult::neutral()->addCacheContexts($contexts);
     $verify($a, $contexts);
-    $b = AccessResult::create()->cachePerRole()->cachePerUser();
+    $b = AccessResult::neutral()->cachePerRole()->cachePerUser();
     $verify($b, $contexts);
-    $c = AccessResult::create()->cachePerUser()->cachePerRole();
+    $c = AccessResult::neutral()->cachePerUser()->cachePerRole();
     $verify($c, $contexts);
     $this->assertEquals($a, $b);
     $this->assertEquals($a, $c);
@@ -390,17 +352,10 @@ public function testCacheContexts() {
       ->will($this->returnValue(FALSE));
     $contexts = array('cache_context.user.roles');
 
-    // Verify the object when using the ::allowIfHasPermission() convenience
-    // instance method.
-    $a = AccessResult::create()->allowIfHasPermission($account, 'may herd llamas');
-    $verify($a, $contexts);
-
     // Verify the object when using the ::allowedIfHasPermission() convenience
     // static method.
     $b = AccessResult::allowedIfHasPermission($account, 'may herd llamas');
     $verify($b, $contexts);
-
-    $this->assertEquals($a, $b);
   }
 
   /**
@@ -420,7 +375,7 @@ public function testCacheTags() {
       $this->assertSame($tags, $access->getCacheTags());
     };
 
-    $access = AccessResult::create()->addCacheTags(['foo' => ['bar']]);
+    $access = AccessResult::neutral()->addCacheTags(['foo' => ['bar']]);
     $verify($access, ['foo' => ['bar' => 'bar']]);
     // Verify resetting works.
     $access->resetCacheTags();
@@ -458,9 +413,9 @@ public function testCacheTags() {
       ->method('getCacheTag')
       ->will($this->returnValue(array('node' => array(20011988))));
     $tags = array('node' => array(20011988 => 20011988));
-    $a = AccessResult::create()->addCacheTags($tags);
+    $a = AccessResult::neutral()->addCacheTags($tags);
     $verify($a, $tags);
-    $b = AccessResult::create()->cacheUntilEntityChanges($node);
+    $b = AccessResult::neutral()->cacheUntilEntityChanges($node);
     $verify($b, $tags);
     $this->assertEquals($a, $b);
   }
diff --git a/core/tests/Drupal/Tests/Core/Access/CustomAccessCheckTest.php b/core/tests/Drupal/Tests/Core/Access/CustomAccessCheckTest.php
index bea19c0..36d330d 100644
--- a/core/tests/Drupal/Tests/Core/Access/CustomAccessCheckTest.php
+++ b/core/tests/Drupal/Tests/Core/Access/CustomAccessCheckTest.php
@@ -97,7 +97,7 @@ public function testAccess() {
 
     $route = new Route('/test-route', array(), array('_custom_access' => '\Drupal\Tests\Core\Access\TestController::accessDeny'));
     $account = $this->getMock('Drupal\Core\Session\AccountInterface');
-    $this->assertEquals(AccessResult::create(), $this->accessChecker->access($route, $route_match, $account));
+    $this->assertEquals(AccessResult::neutral(), $this->accessChecker->access($route, $route_match, $account));
 
     $route = new Route('/test-route', array(), array('_custom_access' => '\Drupal\Tests\Core\Access\TestController::accessAllow'));
     $this->assertEquals(AccessResult::allowed(), $this->accessChecker->access($route, $route_match, $account));
@@ -115,7 +115,7 @@ public function accessAllow() {
   }
 
   public function accessDeny() {
-    return AccessResult::create();
+    return AccessResult::neutral();
   }
 
   public function accessParameter($parameter) {
diff --git a/core/tests/Drupal/Tests/Core/Access/DefaultAccessCheckTest.php b/core/tests/Drupal/Tests/Core/Access/DefaultAccessCheckTest.php
index c7bc1df..8bf0013 100644
--- a/core/tests/Drupal/Tests/Core/Access/DefaultAccessCheckTest.php
+++ b/core/tests/Drupal/Tests/Core/Access/DefaultAccessCheckTest.php
@@ -50,7 +50,7 @@ public function testAccess() {
     $request = new Request(array());
 
     $route = new Route('/test-route', array(), array('_access' => 'NULL'));
-    $this->assertEquals(AccessResult::create(), $this->accessChecker->access($route, $request, $this->account));
+    $this->assertEquals(AccessResult::neutral(), $this->accessChecker->access($route, $request, $this->account));
 
     $route = new Route('/test-route', array(), array('_access' => 'FALSE'));
     $this->assertEquals(AccessResult::forbidden(), $this->accessChecker->access($route, $request, $this->account));
diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityCreateAccessCheckTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityCreateAccessCheckTest.php
index da04fdd..1ee9e1b 100644
--- a/core/tests/Drupal/Tests/Core/Entity/EntityCreateAccessCheckTest.php
+++ b/core/tests/Drupal/Tests/Core/Entity/EntityCreateAccessCheckTest.php
@@ -40,9 +40,9 @@ protected function setUp() {
    * @return array
    */
   public function providerTestAccess() {
-    $no_access = AccessResult::create()->cachePerRole();
+    $no_access = AccessResult::neutral()->cachePerRole();
     $access = AccessResult::allowed()->cachePerRole();
-    $no_access_due_to_errors = AccessResult::create();
+    $no_access_due_to_errors = AccessResult::neutral();
 
     return array(
       array('', 'entity_test', $no_access, $no_access),
diff --git a/core/tests/Drupal/Tests/Core/Route/RoleAccessCheckTest.php b/core/tests/Drupal/Tests/Core/Route/RoleAccessCheckTest.php
index 5fc7123..ad5b577 100644
--- a/core/tests/Drupal/Tests/Core/Route/RoleAccessCheckTest.php
+++ b/core/tests/Drupal/Tests/Core/Route/RoleAccessCheckTest.php
@@ -155,7 +155,7 @@ public function testRoleAccess($path, $grant_accounts, $deny_accounts) {
     foreach ($deny_accounts as $account) {
       $message = sprintf('Access denied for user %s with the roles %s on path: %s', $account->id(), implode(', ', $account->getRoles()), $path);
       $has_access = $role_access_check->access($collection->get($path), $account);
-      $this->assertEquals(AccessResult::create()->cachePerRole(), $has_access, $message);
+      $this->assertEquals(AccessResult::neutral()->cachePerRole(), $has_access, $message);
     }
   }
 
