diff --git a/core/modules/field/lib/Drupal/field/Plugin/views/argument/FieldList.php b/core/modules/field/lib/Drupal/field/Plugin/views/argument/FieldList.php
index d29319d..a9ae7d5 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/views/argument/FieldList.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/views/argument/FieldList.php
@@ -35,7 +35,7 @@ public function init(ViewExecutable $view, DisplayPluginBase $display, array &$o
     parent::init($view, $display, $options);
 
     $field = field_info_field($this->definition['entity_type'], $this->definition['field_name']);
-    $this->allowed_values = options_allowed_values($field);
+    $this->allowed_values = $field->getAllowedValues();
   }
 
   protected function defineOptions() {
diff --git a/core/modules/field/lib/Drupal/field/Plugin/views/argument/ListString.php b/core/modules/field/lib/Drupal/field/Plugin/views/argument/ListString.php
index cc43140..56886ab 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/views/argument/ListString.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/views/argument/ListString.php
@@ -35,7 +35,7 @@ public function init(ViewExecutable $view, DisplayPluginBase $display, array &$o
     parent::init($view, $display, $options);
 
     $field = field_info_field($this->definition['entity_type'], $this->definition['field_name']);
-    $this->allowed_values = options_allowed_values($field);
+    $this->allowed_values = $field->getAllowedValues();
   }
 
   protected function defineOptions() {
diff --git a/core/modules/options/lib/Drupal/options/Plugin/Field/FieldFormatter/OptionsDefaultFormatter.php b/core/modules/options/lib/Drupal/options/Plugin/Field/FieldFormatter/OptionsDefaultFormatter.php
index 5c0b0d2..0983920 100644
--- a/core/modules/options/lib/Drupal/options/Plugin/Field/FieldFormatter/OptionsDefaultFormatter.php
+++ b/core/modules/options/lib/Drupal/options/Plugin/Field/FieldFormatter/OptionsDefaultFormatter.php
@@ -31,10 +31,7 @@ class OptionsDefaultFormatter extends FormatterBase {
    */
   public function viewElements(FieldItemListInterface $items) {
     $elements = array();
-
-    $entity = $items->getEntity();
-    $allowed_values = options_allowed_values($this->fieldDefinition, $entity);
-
+    $allowed_values = $items->getAllowedValues();
     foreach ($items as $delta => $item) {
       if (isset($allowed_values[$item->value])) {
         $output = field_filter_xss($allowed_values[$item->value]);
diff --git a/core/modules/options/lib/Drupal/options/Plugin/Field/FieldType/ListItemBase.php b/core/modules/options/lib/Drupal/options/Plugin/Field/FieldType/ListItemBase.php
index 6e7416b..157f1ba 100644
--- a/core/modules/options/lib/Drupal/options/Plugin/Field/FieldType/ListItemBase.php
+++ b/core/modules/options/lib/Drupal/options/Plugin/Field/FieldType/ListItemBase.php
@@ -18,6 +18,15 @@
 abstract class ListItemBase extends ConfigFieldItemBase implements AllowedValuesInterface {
 
   /**
+   * Cached list of allowed values.
+   *
+   * @see \Drupal\options\Plugin\Field\FieldType\ListItemBase::getAllowedValues()
+   *
+   * @var array
+   */
+  protected $allowedValues;
+
+  /**
    * {@inheritdoc}
    */
   public function getPossibleValues(AccountInterface $account = NULL) {
@@ -48,8 +57,7 @@ public function getSettableValues(AccountInterface $account = NULL) {
    * {@inheritdoc}
    */
   public function getSettableOptions(AccountInterface $account = NULL) {
-    $allowed_options = options_allowed_values($this->getFieldDefinition(), $this->getEntity());
-    return $allowed_options;
+    return $this->getAllowedValues();
   }
 
   /**
@@ -157,6 +165,35 @@ public function settingsForm(array $form, array &$form_state, $has_data) {
   }
 
   /**
+   * Returns the array of allowed values for a list field.
+   *
+   * The strings are not safe for output. Keys and values of the array need to
+   * be sanitized through field_filter_xss() for output.
+   *
+   * @return array
+   *   The array of allowed values. Keys of the array are the raw stored values
+   *   (number or text), values of the array are the display labels.
+   */
+  public function getAllowedValues() {
+    if (isset($this->allowedValues)) {
+      return $this->allowedValues;
+    }
+    $callback = $this->getFieldDefinition()->getSetting('allowed_values_function');
+    // If $cacheable is FALSE, then the allowed values are not statically
+    // cached. See options_test_dynamic_values_callback() for an example of
+    // generating dynamic and uncached values.
+    $cacheable = TRUE;
+    if (!empty($callback)) {
+      $values = $callback($this->getFieldDefinition(), $this->getEntity(), $cacheable);
+      $this->allowedValues = $values;
+    }
+    else {
+      $values = $this->getFieldDefinition()->getSetting('allowed_values');
+    }
+    return $values;
+  }
+
+  /**
    * Generates a string representation of an array of 'allowed values'.
    *
    * This string format is suitable for edition in a textarea.
@@ -214,7 +251,7 @@ public function validateAllowedValues($element, &$form_state) {
       // Prevent removing values currently in use.
       if ($has_data) {
         $lost_keys = array_diff(array_keys($this->getSetting('allowed_values')), array_keys($values));
-        if (_options_values_in_use($this->getEntity()->getEntityTypeId(), $this->getFieldDefinition()->getName(), $lost_keys)) {
+        if ($this->isValueInUse($lost_keys)) {
           \Drupal::formBuilder()->setError($element, $form_state, t('Allowed values list: some values are being removed while currently in use.'));
         }
       }
@@ -224,6 +261,31 @@ public function validateAllowedValues($element, &$form_state) {
   }
 
   /**
+   * Returns whether a value (or list of values) is used in current field values.
+   *
+   * @param string|array $value
+   *   The value or a list of values to check.
+   *
+   * @return bool
+   *   TRUE if the value(s) are used, FALSE otherwise.
+   */
+  public function isValueInUse($value) {
+    if (empty($value)) {
+      return FALSE;
+    }
+    $values = (array) $value;
+
+    $factory = \Drupal::service('entity.query');
+    $result = $factory->get($this->getEntity()->getEntityTypeId())
+      ->condition($this->getFieldDefinition()->getName() . '.value', $values)
+      ->count()
+      ->accessCheck(FALSE)
+      ->range(0, 1)
+      ->execute();
+    return (bool) $result;
+  }
+
+  /**
    * Parses a string of 'allowed values' into an array.
    *
    * @param string $string
diff --git a/core/modules/options/options.module b/core/modules/options/options.module
index 51d568a..e868180 100644
--- a/core/modules/options/options.module
+++ b/core/modules/options/options.module
@@ -6,9 +6,6 @@
  */
 
 use Drupal\Component\Utility\NestedArray;
-use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Field\FieldDefinitionInterface;
-use Drupal\field\FieldConfigInterface;
 use Drupal\field\FieldUpdateForbiddenException;
 
 /**
@@ -43,63 +40,6 @@ function options_field_settings_form_value_boolean_allowed_values($element, $inp
 }
 
 /**
- * Implements hook_ENTITY_TYPE_update() for 'field_config'.
- */
-function options_field_config_update(FieldConfigInterface $field) {
-  drupal_static_reset('options_allowed_values');
-}
-
-/**
- * Implements hook_ENTITY_TYPE_delete() for 'field_config'.
- */
-function options_field_config_delete(FieldConfigInterface $field) {
-  drupal_static_reset('options_allowed_values');
-}
-
-/**
- * Returns the array of allowed values for a list field.
- *
- * The strings are not safe for output. Keys and values of the array should be
- * sanitized through field_filter_xss() before being displayed.
- *
- * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
- *   The field definition.
- * @param \Drupal\Core\Entity\EntityInterface $entity
- *   The entity object.
- *
- * @return
- *   The array of allowed values. Keys of the array are the raw stored values
- *   (number or text), values of the array are the display labels.
- */
-function options_allowed_values(FieldDefinitionInterface $field_definition, EntityInterface $entity) {
-  $allowed_values = &drupal_static(__FUNCTION__, array());
-
-  $cache_id = implode(':', array($entity->getEntityTypeId(), $entity->bundle(), $field_definition->getName()));
-  if (!isset($allowed_values[$cache_id])) {
-    $function = $field_definition->getSetting('allowed_values_function');
-    // If $cacheable is FALSE, then the allowed values are not statically
-    // cached. See options_test_dynamic_values_callback() for an example of
-    // generating dynamic and uncached values.
-    $cacheable = TRUE;
-    if (!empty($function)) {
-      $values = $function($field_definition, $entity, $cacheable);
-    }
-    else {
-      $values = $field_definition->getSetting('allowed_values');
-    }
-
-    if ($cacheable) {
-      $allowed_values[$cache_id] = $values;
-    }
-    else {
-      return $values;
-    }
-  }
-
-  return $allowed_values[$cache_id];
-}
-
-/**
  * Implements hook_field_update_forbid().
  */
 function options_field_update_forbid($field, $prior_field) {
@@ -108,28 +48,8 @@ function options_field_update_forbid($field, $prior_field) {
     $allowed_values = $field->getSetting('allowed_values');
     $prior_allowed_values = $prior_field->getSetting('allowed_values');
     $lost_keys = array_diff(array_keys($prior_allowed_values), array_keys($allowed_values));
-    if (_options_values_in_use($field->entity_type, $field->getName(), $lost_keys)) {
+    if ($field->isValueInUse($lost_keys)) {
       throw new FieldUpdateForbiddenException(t('A list field (@field_name) with existing data cannot have its keys changed.', array('@field_name' => $field->getName())));
     }
   }
 }
-
-/**
- * Checks if a list of values are being used in actual field values.
- */
-function _options_values_in_use($entity_type, $field_name, $values) {
-  if ($values) {
-    $factory = \Drupal::service('entity.query');
-    $result = $factory->get($entity_type)
-      ->condition($field_name . '.value', $values)
-      ->count()
-      ->accessCheck(FALSE)
-      ->range(0, 1)
-      ->execute();
-    if ($result) {
-      return TRUE;
-    }
-  }
-
-  return FALSE;
-}
