diff --git a/core/core.services.yml b/core/core.services.yml
index 03b8c7c..db46b57 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -365,12 +365,6 @@ services:
       - { name: event_subscriber }
     arguments: ['@language_manager']
     scope: request
-  redirect_response_subscriber:
-    class: Drupal\Core\EventSubscriber\RedirectResponseSubscriber
-    arguments: ['@url_generator']
-    tags:
-      - { name: event_subscriber }
-    scope: request
   request_close_subscriber:
     class: Drupal\Core\EventSubscriber\RequestCloseSubscriber
     tags:
diff --git a/core/includes/batch.inc b/core/includes/batch.inc
index 27fb632..3fe9bb0 100644
--- a/core/includes/batch.inc
+++ b/core/includes/batch.inc
@@ -15,8 +15,7 @@
  */
 
 use Drupal\Core\Batch\Percentage;
-use Symfony\Component\HttpFoundation\JsonResponse;
-use Symfony\Component\HttpFoundation\RedirectResponse;
+use \Symfony\Component\HttpFoundation\JsonResponse;
 
 /**
  * Renders the batch processing page based on the current state of the batch.
@@ -35,7 +34,7 @@ function _batch_page() {
     $batch = Drupal::service('batch.storage')->load($_REQUEST['id']);
     if (!$batch) {
       drupal_set_message(t('No active batch.'), 'error');
-      return new RedirectResponse(url('<front>', array('absolute' => TRUE)));
+      drupal_goto();
     }
   }
 
@@ -413,7 +412,7 @@ function _batch_finished() {
   if ($_batch['progressive']) {
     // Revert the 'destination' that was saved in batch_process().
     if (isset($_batch['destination'])) {
-      Drupal::request()->query->set('destination', $_batch['destination']);
+      $_GET['destination'] = $_batch['destination'];
     }
 
     // Determine the target path to redirect to.
@@ -427,10 +426,7 @@ function _batch_finished() {
     }
 
     // Use drupal_redirect_form() to handle the redirection logic.
-    $redirect = drupal_redirect_form($_batch['form_state']);
-    if (is_object($redirect)) {
-      return $redirect;
-    }
+    drupal_redirect_form($_batch['form_state']);
 
     // If no redirection happened, redirect to the originating page. In case the
     // form needs to be rebuilt, save the final $form_state for
@@ -442,14 +438,6 @@ function _batch_finished() {
     if (function_exists($function)) {
       $function($_batch['source_url'], array('query' => array('op' => 'finish', 'id' => $_batch['id'])));
     }
-    elseif ($function === NULL) {
-      // Default to RedirectResponse objects when nothing specified.
-      $url = url($_batch['source_url'], array(
-        'absolute' => TRUE,
-        'query' => array('op' => 'finish', 'id' => $_batch['id']),
-      ));
-      return new RedirectResponse($url);
-    }
   }
 }
 
diff --git a/core/includes/common.inc b/core/includes/common.inc
index d8638fe..e5bf937 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -503,7 +503,7 @@ function drupal_http_build_query(array $query, $parent = '') {
 }
 
 /**
- * Prepares a 'destination' URL query parameter for use with url().
+ * Prepares a 'destination' URL query parameter for use with drupal_goto().
  *
  * Used to direct the user back to the referring page after completing a form.
  * By default the current URL is returned. If a destination exists in the
@@ -516,6 +516,7 @@ function drupal_http_build_query(array $query, $parent = '') {
  *     not available, the current path.
  *
  * @see current_path()
+ * @see drupal_goto()
  */
 function drupal_get_destination() {
   $destination = &drupal_static(__FUNCTION__);
@@ -569,6 +570,7 @@ function drupal_get_destination() {
  *   - 'fragment': The fragment of $url, if existent.
  *
  * @see url()
+ * @see drupal_goto()
  * @ingroup php_wrappers
  */
 function drupal_parse_url($url) {
@@ -628,6 +630,84 @@ function drupal_encode_path($path) {
 }
 
 /**
+ * Sends the user to a different Drupal page.
+ *
+ * This issues an on-site HTTP redirect. The function makes sure the redirected
+ * URL is formatted correctly.
+ *
+ * If a destination was specified in the current request's URI (i.e.,
+ * $_GET['destination']) then it will override the $path and $options values
+ * passed to this function. This provides the flexibility to build a link to
+ * user/login and override the default redirection so that the user is
+ * redirected to a specific path after logging in:
+ * @code
+ *   $query = array('destination' => "node/$node->nid");
+ *   $link = l(t('Log in'), 'user/login', array('query' => $query));
+ * @endcode
+ *
+ * Drupal will ensure that messages set by drupal_set_message() and other
+ * session data are written to the database before the user is redirected.
+ *
+ * This function ends the request; use it instead of a return in your menu
+ * callback.
+ *
+ * @param $path
+ *   (optional) A Drupal path or a full URL, which will be passed to url() to
+ *   compute the redirect for the URL.
+ * @param $options
+ *   (optional) An associative array of additional URL options to pass to url().
+ * @param $http_response_code
+ *   (optional) The HTTP status code to use for the redirection, defaults to
+ *   302. The valid values for 3xx redirection status codes are defined in
+ *   @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3 RFC 2616 @endlink
+ *   and the
+ *   @link http://tools.ietf.org/html/draft-reschke-http-status-308-07 draft for the new HTTP status codes: @endlink
+ *   - 301: Moved Permanently (the recommended value for most redirects).
+ *   - 302: Found (default in Drupal and PHP, sometimes used for spamming search
+ *     engines).
+ *   - 303: See Other.
+ *   - 304: Not Modified.
+ *   - 305: Use Proxy.
+ *   - 307: Temporary Redirect.
+ *
+ * @see drupal_get_destination()
+ * @see url()
+ */
+function drupal_goto($path = '', array $options = array(), $http_response_code = 302) {
+  // A destination in $_GET always overrides the function arguments.
+  // We do not allow absolute URLs to be passed via $_GET, as this can be an
+  // attack vector, with the following exception:
+  // - Absolute URLs that point to this site (i.e. same base URL and
+  //   base path) are allowed.
+  if (isset($_GET['destination']) && (!url_is_external($_GET['destination']) || _external_url_is_local($_GET['destination']))) {
+    $destination = drupal_parse_url($_GET['destination']);
+    $path = $destination['path'];
+    $options['query'] = $destination['query'];
+    $options['fragment'] = $destination['fragment'];
+  }
+
+  drupal_alter('drupal_goto', $path, $options, $http_response_code);
+
+  // The 'Location' HTTP header must be absolute.
+  $options['absolute'] = TRUE;
+
+  $url = Drupal::urlGenerator()->generateFromPath($path, $options);
+
+  if (drupal_get_bootstrap_phase() == DRUPAL_BOOTSTRAP_FULL) {
+    drupal_session_commit();
+  }
+
+  $response = new RedirectResponse($url, $http_response_code);
+  // @todo We should not send the response here: http://drupal.org/node/1668866
+  $response->sendHeaders();
+
+  // The "Location" header sends a redirect status code to the HTTP daemon. In
+  // some cases this can be wrong, so we make sure none of the code below the
+  // drupal_goto() call gets executed upon redirection.
+  exit;
+}
+
+/**
  * Determines if an external URL points to this Drupal installation.
  *
  * @param $url
diff --git a/core/includes/form.inc b/core/includes/form.inc
index 4689711..b23bd28 100644
--- a/core/includes/form.inc
+++ b/core/includes/form.inc
@@ -14,10 +14,6 @@
 use Drupal\Core\Template\Attribute;
 use Drupal\Core\Datetime\DrupalDateTime;
 use Drupal\Core\Utility\Color;
-use Symfony\Component\HttpFoundation\Response;
-use Symfony\Component\HttpFoundation\RedirectResponse;
-use Symfony\Component\HttpKernel\KernelEvents;
-use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
 
 /**
  * @defgroup forms Form builder functions
@@ -231,8 +227,9 @@ function drupal_get_form($form_arg) {
  *     errors.
  *   - redirect: Used to redirect the form on submission. It may either be a
  *     string containing the destination URL, or an array of arguments
- *     compatible with url(). See url() for complete information.
- *   - no_redirect: If set to TRUE the form will NOT perform a redirect,
+ *     compatible with drupal_goto(). See drupal_redirect_form() for complete
+ *     information.
+ *   - no_redirect: If set to TRUE the form will NOT perform a drupal_goto(),
  *     even if 'redirect' is set.
  *   - method: The HTTP form method to use for finding the input for this form.
  *     May be 'post' or 'get'. Defaults to 'post'. Note that 'get' method
@@ -416,12 +413,7 @@ function drupal_build_form($form_id, &$form_state) {
   //   appropriate information persists to the next page request.
   // All of the handlers in the pipeline receive $form_state by reference and
   // can use it to know or update information about the state of the form.
-  $response = drupal_process_form($form_id, $form, $form_state);
-
-  // If the form returns some kind of response, deliver it.
-  if ($response instanceof Response) {
-    _drupal_form_send_response($response);
-  }
+  drupal_process_form($form_id, $form, $form_state);
 
   // If this was a successful submission of a single-step form or the last step
   // of a multi-step form, then drupal_process_form() issued a redirect to
@@ -866,10 +858,6 @@ function drupal_retrieve_form($form_id, &$form_state) {
   // If $callback was returned by a hook_forms() implementation, call it.
   // Otherwise, call the function named after the form id.
   $form = call_user_func_array($callback, $args);
-  // If the form returns some kind of response, deliver it.
-  if ($form instanceof Response) {
-    _drupal_form_send_response($form);
-  }
   $form['#form_id'] = $form_id;
 
   return $form;
@@ -953,10 +941,7 @@ function drupal_process_form($form_id, &$form, &$form_state) {
         }
 
         $batch['progressive'] = !$form_state['programmed'];
-        $response = batch_process();
-        if ($batch['progressive']) {
-          return $response;
-        }
+        batch_process();
 
         // Execution continues only for programmatic forms.
         // For 'regular' forms, we get redirected to the batch processing
@@ -968,10 +953,7 @@ function drupal_process_form($form_id, &$form, &$form_state) {
       $form_state['executed'] = TRUE;
 
       // Redirect the form based on values in $form_state.
-      $redirect = drupal_redirect_form($form_state);
-      if (is_object($redirect)) {
-        return $redirect;
-      }
+      drupal_redirect_form($form_state);
     }
 
     // Don't rebuild or cache form submissions invoked via drupal_form_submit().
@@ -1263,10 +1245,10 @@ function drupal_validate_form($form_id, &$form, &$form_state) {
  *
  * Usually (for exceptions, see below) $form_state['redirect'] determines where
  * to redirect the user. This can be set either to a string (the path to
- * redirect to), or an array of arguments for url(). If $form_state['redirect']
- * is missing, the user is usually (again, see below for exceptions) redirected
- * back to the page they came from, where they should see a fresh, unpopulated
- * copy of the form.
+ * redirect to), or an array of arguments for drupal_goto(). If
+ * $form_state['redirect'] is missing, the user is usually (again, see below for
+ * exceptions) redirected back to the page they came from, where they should see
+ * a fresh, unpopulated copy of the form.
  *
  * Here is an example of how to set up a form to redirect to the path 'node':
  * @code
@@ -1297,11 +1279,12 @@ function drupal_validate_form($form_id, &$form, &$form_state) {
  *   form builder functions or form validation/submit handlers.
  * - If $form_state['redirect'] is set to FALSE, redirection is disabled.
  * - If none of the above conditions has prevented redirection, then the
- *   redirect is accomplished by returning a RedirectResponse, passing in the
- *   value of $form_state['redirect'] if it is set, or the current path if it is
- *   not. RedirectResponse preferentially uses the value of $_GET['destination']
+ *   redirect is accomplished by calling drupal_goto(), passing in the value of
+ *   $form_state['redirect'] if it is set, or the current path if it is
+ *   not. drupal_goto() preferentially uses the value of $_GET['destination']
  *   (the 'destination' URL query string) if it is present, so this will
- *   override any values set by $form_state['redirect'].
+ *   override any values set by $form_state['redirect']. Note that during
+ *   installation, install_goto() is called in place of drupal_goto().
  *
  * @param $form_state
  *   An associative array containing the current state of the form.
@@ -1322,33 +1305,22 @@ function drupal_redirect_form($form_state) {
   if (!empty($form_state['no_redirect'])) {
     return;
   }
-  // Only invoke a redirection if redirect value was not set to FALSE.
+  // Only invoke drupal_goto() if redirect value was not set to FALSE.
   if (!isset($form_state['redirect']) || $form_state['redirect'] !== FALSE) {
     if (isset($form_state['redirect'])) {
       if (is_array($form_state['redirect'])) {
-        $options = isset($form_state['redirect'][1]) ? $form_state['redirect'][1] : array();
-        // Redirections should always use absolute URLs.
-        $options['absolute'] = TRUE;
-        $status_code =  isset($form_state['redirect'][2]) ? $form_state['redirect'][2] : 302;
-        return new RedirectResponse(url($form_state['redirect'][0], $options), $status_code);
+        call_user_func_array('drupal_goto', $form_state['redirect']);
       }
       else {
         // This function can be called from the installer, which guarantees
         // that $redirect will always be a string, so catch that case here
         // and use the appropriate redirect function.
-        if (drupal_installation_attempted()) {
-          install_goto($form_state['redirect']);
-        }
-        else {
-          return new RedirectResponse(url($form_state['redirect'], array('absolute' => TRUE)));
-        }
+        $function = drupal_installation_attempted() ? 'install_goto' : 'drupal_goto';
+        $function($form_state['redirect']);
       }
     }
-    $url = url(Drupal::request()->attributes->get('system_path'), array(
-      'query' => Drupal::request()->query->all(),
-      'absolute' => TRUE,
-    ));
-    return new RedirectResponse($url);
+    $request = Drupal::request();
+    drupal_goto($request->attributes->get('system_path'), array('query' => $request->query->all()));
   }
 }
 
@@ -4874,28 +4846,6 @@ function _form_set_attributes(&$element, $class = array()) {
 }
 
 /**
- * Triggers kernel.response and sends a form response.
- *
- * @deprecated This function is to be used internally by Form API only.
- *
- * @param \Symfony\Component\HttpFoundation\Response $response
- *   A response object.
- */
-function _drupal_form_send_response(Response $response) {
-  $request = Drupal::request();
-  $kernel = Drupal::service('http_kernel');
-  $event = new FilterResponseEvent($kernel, $request, $kernel::MASTER_REQUEST, $response);
-
-  Drupal::service('event_dispatcher')->dispatch(KernelEvents::RESPONSE, $event);
-  // Prepare and send the response.
-  $event->getResponse()
-    ->prepare($request)
-    ->send();
-  $kernel->terminate($request, $response);
-  exit;
-}
-
-/**
  * @} End of "defgroup form_api".
  */
 
@@ -5117,6 +5067,9 @@ function batch_set($batch_definition) {
 /**
  * Processes the batch.
  *
+ * Unless the batch has been marked with 'progressive' = FALSE, the function
+ * issues a drupal_goto and thus ends page execution.
+ *
  * This function is generally not needed in form submit handlers;
  * Form API takes care of batches that were set during form submission.
  *
@@ -5127,12 +5080,11 @@ function batch_set($batch_definition) {
  *   URL of the batch processing page.
  * @param $redirect_callback
  *   (optional) Specify a function to be called to redirect to the progressive
- *   processing page.
- *
- * @return \Symfony\Component\HttpFoundation\RedirectResponse|null
- *   A redirect response if the batch is progressive. No return value otherwise.
+ *   processing page. By default drupal_goto() will be used to redirect to a
+ *   page which will do the progressive page. Specifying another function will
+ *   allow the progressive processing to be processed differently.
  */
-function batch_process($redirect = NULL, $url = 'batch', $redirect_callback = NULL) {
+function batch_process($redirect = NULL, $url = 'batch', $redirect_callback = 'drupal_goto') {
   $batch =& batch_get();
 
   drupal_theme_initialize();
@@ -5172,12 +5124,11 @@ function batch_process($redirect = NULL, $url = 'batch', $redirect_callback = NU
       // the generic error message.
       $batch['error_message'] = t('Please continue to <a href="@error_url">the error page</a>', array('@error_url' => url($url, array('query' => array('id' => $batch['id'], 'op' => 'finished')))));
 
-      // Clear the way for the redirection to the batch processing page, by
-      // saving and unsetting the 'destination', if there is any.
-      $request = Drupal::request();
-      if ($request->query->has('destination')) {
-        $batch['destination'] = $request->query->get('destination');
-        $request->query->remove('destination');
+      // Clear the way for the drupal_goto() redirection to the batch processing
+      // page, by saving and unsetting the 'destination', if there is any.
+      if (isset($_GET['destination'])) {
+        $batch['destination'] = $_GET['destination'];
+        unset($_GET['destination']);
       }
 
       // Store the batch.
@@ -5187,14 +5138,8 @@ function batch_process($redirect = NULL, $url = 'batch', $redirect_callback = NU
       $_SESSION['batches'][$batch['id']] = TRUE;
 
       // Redirect for processing.
-      $options = array('query' => array('op' => 'start', 'id' => $batch['id']));
-      if (($function = $batch['redirect_callback']) && function_exists($function)) {
-        $function($batch['url'], $options);
-      }
-      else {
-        $options['absolute'] = TRUE;
-        return new RedirectResponse(url($batch['url'], $options));
-      }
+      $function = $batch['redirect_callback'];
+      $function($batch['url'], array('query' => array('op' => 'start', 'id' => $batch['id'])));
     }
     else {
       // Non-progressive execution: bypass the whole progressbar workflow
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index 1ecd819..e7ee511 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -626,14 +626,7 @@ function install_run_task($task, &$install_state) {
       }
       // Process the batch. For progressive batches, this will redirect.
       // Otherwise, the batch will complete.
-      $response = batch_process(install_redirect_url($install_state), install_full_redirect_url($install_state));
-      if ($response instanceof Response) {
-        // Save $_SESSION data from batch.
-        drupal_session_commit();
-        // Send the response.
-        $response->send();
-        exit;
-      }
+      batch_process(install_redirect_url($install_state), install_full_redirect_url($install_state));
     }
     // If we are in the middle of processing this batch, keep sending back
     // any output from the batch process, until the task is complete.
diff --git a/core/includes/update.inc b/core/includes/update.inc
index 7ccda5a..5dc0d5f 100644
--- a/core/includes/update.inc
+++ b/core/includes/update.inc
@@ -830,7 +830,7 @@ function update_do_one($module, $number, $dependency_map, &$context) {
  *
  * @see update_resolve_dependencies()
  */
-function update_batch($start, $redirect = NULL, $url = NULL, $batch = array(), $redirect_callback = NULL) {
+function update_batch($start, $redirect = NULL, $url = NULL, $batch = array(), $redirect_callback = 'drupal_goto') {
   // During the update, bring the site offline so that schema changes do not
   // affect visiting users.
   $maintenance_mode = config('system.maintenance')->get('enabled');
@@ -883,7 +883,7 @@ function update_batch($start, $redirect = NULL, $url = NULL, $batch = array(), $
     'file' => 'core/includes/update.inc',
   );
   batch_set($batch);
-  return batch_process($redirect, $url, $redirect_callback);
+  batch_process($redirect, $url, $redirect_callback);
 }
 
 /**
diff --git a/core/lib/Drupal/Core/Entity/EntityFormController.php b/core/lib/Drupal/Core/Entity/EntityFormController.php
index 7c5f7ed..79dc7f4 100644
--- a/core/lib/Drupal/Core/Entity/EntityFormController.php
+++ b/core/lib/Drupal/Core/Entity/EntityFormController.php
@@ -372,13 +372,13 @@ protected function submitEntityLanguage(array $form, array &$form_state) {
       $current_langcode = $entity->language()->langcode == $form_langcode ? $form_state['values']['langcode'] : $form_langcode;
 
       foreach (field_info_instances($entity_type, $entity->bundle()) as $instance) {
-        $field_name = $instance['field_name'];
+        $field_name = $instance->getFieldName();
         $field = field_info_field($field_name);
         $previous_langcode = $form[$field_name]['#language'];
 
         // Handle a possible language change: new language values are inserted,
         // previous ones are deleted.
-        if ($field['translatable'] && $previous_langcode != $current_langcode) {
+        if ($field->translatable && $previous_langcode != $current_langcode) {
           $form_state['values'][$field_name][$current_langcode] = $form_state['values'][$field_name][$previous_langcode];
           $form_state['values'][$field_name][$previous_langcode] = array();
         }
diff --git a/core/lib/Drupal/Core/EventSubscriber/RedirectResponseSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/RedirectResponseSubscriber.php
deleted file mode 100644
index 9da318e..0000000
--- a/core/lib/Drupal/Core/EventSubscriber/RedirectResponseSubscriber.php
+++ /dev/null
@@ -1,81 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\EventSubscriber\RedirectResponseSubscriber.
- */
-
-namespace Drupal\Core\EventSubscriber;
-
-use Drupal\Core\Routing\PathBasedGeneratorInterface;
-use Symfony\Component\HttpKernel\KernelEvents;
-use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
-use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
-use Symfony\Component\HttpFoundation\RedirectResponse;
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-
-/**
- * Access subscriber for controller requests.
- */
-class RedirectResponseSubscriber implements EventSubscriberInterface {
-
-  /**
-   * The url generator service.
-   *
-   * @var \Drupal\Core\Routing\PathBasedGeneratorInterface
-   */
-  protected $urlGenerator;
-
-  /**
-   * Constructs a RedirectResponseSubscriber object.
-   *
-   * @param \Drupal\Core\Routing\PathBasedGeneratorInterface $url_generator
-   *   The url generator service.
-   */
-  public function __construct(PathBasedGeneratorInterface $url_generator) {
-    $this->urlGenerator = $url_generator;
-  }
-
-  /**
-   * Allows manipulation of the response object when performing a redirect.
-   *
-   * @param Symfony\Component\HttpKernel\Event\FilterResponseEvent $event
-   *   The Event to process.
-   */
-  public function checkRedirectUrl(FilterResponseEvent $event) {
-    $response = $event->getResponse();
-    if ($response instanceOf RedirectResponse) {
-      $options = array();
-
-      $redirect_path = $response->getTargetUrl();
-      $destination = $event->getRequest()->query->get('destination');
-      // A destination in $_GET always overrides the current RedirectResponse.
-      // We do not allow absolute URLs to be passed via $_GET, as this can be an
-      // attack vector, with the following exception:
-      // - Absolute URLs that point to this site (i.e. same base URL and
-      //   base path) are allowed.
-      if ($destination && (!url_is_external($destination) || _external_url_is_local($destination))) {
-        $destination = drupal_parse_url($destination);
-
-        $path = $destination['path'];
-        $options['query'] = $destination['query'];
-        $options['fragment'] = $destination['fragment'];
-        // The 'Location' HTTP header must always be absolute.
-        $options['absolute'] = TRUE;
-
-        $response->setTargetUrl($this->urlGenerator->generateFromPath($path, $options));
-      }
-    }
-  }
-
-  /**
-   * Registers the methods in this class that should be listeners.
-   *
-   * @return array
-   *   An array of event listener definitions.
-   */
-  static function getSubscribedEvents() {
-    $events[KernelEvents::RESPONSE][] = array('checkRedirectUrl');
-    return $events;
-  }
-}
diff --git a/core/modules/action/lib/Drupal/action/Plugin/Action/GotoAction.php b/core/modules/action/lib/Drupal/action/Plugin/Action/GotoAction.php
index c20801a..aff20b0 100644
--- a/core/modules/action/lib/Drupal/action/Plugin/Action/GotoAction.php
+++ b/core/modules/action/lib/Drupal/action/Plugin/Action/GotoAction.php
@@ -10,11 +10,6 @@
 use Drupal\Core\Annotation\Action;
 use Drupal\Core\Annotation\Translation;
 use Drupal\Core\Action\ConfigurableActionBase;
-use Drupal\Core\Routing\PathBasedGeneratorInterface;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-use Symfony\Component\EventDispatcher\EventDispatcherInterface;
-use Symfony\Component\HttpFoundation\RedirectResponse;
-use Symfony\Component\HttpKernel\KernelEvents;
 
 /**
  * Redirects to a different URL.
@@ -28,59 +23,10 @@
 class GotoAction extends ConfigurableActionBase {
 
   /**
-   * The event dispatcher service.
-   *
-   * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
-   */
-  protected $dispatcher;
-
-  /**
-   * The url generator service.
-   *
-   * @var \Drupal\Core\Routing\PathBasedGeneratorInterface
-   */
-  protected $urlGenerator;
-
-  /**
-   * Constructs a new DeleteNode object.
-   *
-   * @param array $configuration
-   *   A configuration array containing information about the plugin instance.
-   * @param string $plugin_id
-   *   The plugin ID for the plugin instance.
-   * @param array $plugin_definition
-   *   The plugin implementation definition.
-   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher
-   *   The tempstore factory.
-   * @param \Drupal\Core\Routing\PathBasedGeneratorInterface $url_generator
-   *   The url generator service.
-   */
-  public function __construct(array $configuration, $plugin_id, array $plugin_definition, EventDispatcherInterface $dispatcher, PathBasedGeneratorInterface $url_generator) {
-    parent::__construct($configuration, $plugin_id, $plugin_definition);
-
-    $this->dispatcher = $dispatcher;
-    $this->urlGenerator = $url_generator;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container, array $configuration, $plugin_id, array $plugin_definition) {
-    return new static($configuration, $plugin_id, $plugin_definition, $container->get('event_dispatcher'), $container->get('url_generator'));
-  }
-
-  /**
    * {@inheritdoc}
    */
   public function execute($object = NULL) {
-    $url = $this->urlGenerator
-      ->generateFromPath($this->configuration['url'], array('absolute' => TRUE));
-    $response = new RedirectResponse($url);
-    $listener = function($event) use ($response) {
-      $event->setResponse($response);
-    };
-    // Add the listener to the event dispatcher.
-    $this->dispatcher->addListener(KernelEvents::RESPONSE, $listener);
+    drupal_goto($this->configuration['url']);
   }
 
   /**
diff --git a/core/modules/aggregator/tests/modules/aggregator_test/aggregator_test.module b/core/modules/aggregator/tests/modules/aggregator_test/aggregator_test.module
index 4427a3a..b18f87b 100644
--- a/core/modules/aggregator/tests/modules/aggregator_test/aggregator_test.module
+++ b/core/modules/aggregator/tests/modules/aggregator_test/aggregator_test.module
@@ -1,7 +1,6 @@
 <?php
 
 use Drupal\Component\Utility\Crypt;
-use Symfony\Component\HttpFoundation\RedirectResponse;
 
 /**
  * Implements hook_menu().
@@ -71,5 +70,5 @@ function aggregator_test_feed($use_last_modified = FALSE, $use_etag = FALSE) {
  * Page callback that redirects to another feed.
  */
 function aggregator_test_redirect() {
-  return new RedirectResponse(url('aggregator/test-feed', array('absolute' => TRUE)), 301);
+  drupal_goto('aggregator/test-feed', array(), 301);
 }
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockFieldTest.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockFieldTest.php
index da5ac4f..00f575c 100644
--- a/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockFieldTest.php
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockFieldTest.php
@@ -80,12 +80,12 @@ public function testBlockFields() {
     ));
     $this->instance->save();
     entity_get_form_display('custom_block', 'link', 'default')
-      ->setComponent($this->field['field_name'], array(
+      ->setComponent($this->field->id(), array(
         'type' => 'link_default',
       ))
       ->save();
     entity_get_display('custom_block', 'link', 'default')
-      ->setComponent($this->field['field_name'], array(
+      ->setComponent($this->field->id(), array(
         'type' => 'link',
         'label' => 'hidden',
       ))
@@ -95,8 +95,8 @@ public function testBlockFields() {
     $this->drupalGet('block/add/link');
     $edit = array(
       'info' => $this->randomName(8),
-      $this->field['field_name'] . '[und][0][url]' => 'http://example.com',
-      $this->field['field_name'] . '[und][0][title]' => 'Example.com'
+      $this->field->id() . '[und][0][url]' => 'http://example.com',
+      $this->field->id() . '[und][0][title]' => 'Example.com'
     );
     $this->drupalPost(NULL, $edit, t('Save'));
     // Place the block.
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockTypeTest.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockTypeTest.php
index 35f4b98..6d9adb8 100644
--- a/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockTypeTest.php
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockTypeTest.php
@@ -79,7 +79,7 @@ public function testCustomBlockTypeEditing() {
     $this->createCustomBlockType('other');
 
     $instance = field_info_instance('custom_block', 'block_body', 'basic');
-    $this->assertEqual($instance['label'], 'Block body', 'Body field was found.');
+    $this->assertEqual($instance->label(), 'Block body', 'Body field was found.');
 
     // Verify that title and body fields are displayed.
     $this->drupalGet('block/add/basic');
diff --git a/core/modules/comment/comment.admin.inc b/core/modules/comment/comment.admin.inc
index b2a13a1..3890a1a 100644
--- a/core/modules/comment/comment.admin.inc
+++ b/core/modules/comment/comment.admin.inc
@@ -6,7 +6,6 @@
  */
 
 use Drupal\comment\Plugin\Core\Entity\Comment;
-use Symfony\Component\HttpFoundation\RedirectResponse;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 
 /**
@@ -239,7 +238,7 @@ function comment_multiple_delete_confirm($form, &$form_state) {
 
   if (!$comment_counter) {
     drupal_set_message(t('There do not appear to be any comments to delete, or your selected comment was deleted by another administrator.'));
-    return new RedirectResponse(url('admin/content/comment', array('absolute' => TRUE)));
+    drupal_goto('admin/content/comment');
   }
   else {
     return confirm_form($form,
diff --git a/core/modules/comment/comment.pages.inc b/core/modules/comment/comment.pages.inc
index 2fbcb58..5e1b190 100644
--- a/core/modules/comment/comment.pages.inc
+++ b/core/modules/comment/comment.pages.inc
@@ -7,7 +7,6 @@
 
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\comment\Plugin\Core\Entity\Comment;
-use Symfony\Component\HttpFoundation\RedirectResponse;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 
 /**
@@ -48,7 +47,7 @@ function comment_reply(EntityInterface $node, $pid = NULL) {
     }
     else {
       drupal_set_message(t('You are not authorized to post comments.'), 'error');
-      return new RedirectResponse(url("node/$node->nid", array('absolute' => TRUE)));
+      drupal_goto("node/$node->nid");
     }
   }
   else {
@@ -63,19 +62,19 @@ function comment_reply(EntityInterface $node, $pid = NULL) {
           if ($comment->nid->target_id != $node->nid) {
             // Attempting to reply to a comment not belonging to the current nid.
             drupal_set_message(t('The comment you are replying to does not exist.'), 'error');
-            return new RedirectResponse(url("node/$node->nid", array('absolute' => TRUE)));
+            drupal_goto("node/$node->nid");
           }
           // Display the parent comment
           $build['comment_parent'] = comment_view($comment);
         }
         else {
           drupal_set_message(t('The comment you are replying to does not exist.'), 'error');
-          return new RedirectResponse(url("node/$node->nid", array('absolute' => TRUE)));
+          drupal_goto("node/$node->nid");
         }
       }
       else {
         drupal_set_message(t('You are not authorized to view comments.'), 'error');
-        return new RedirectResponse(url("node/$node->nid", array('absolute' => TRUE)));
+        drupal_goto("node/$node->nid");
       }
     }
     // This is the case where the comment is in response to a node. Display the node.
@@ -86,14 +85,14 @@ function comment_reply(EntityInterface $node, $pid = NULL) {
     // Should we show the reply box?
     if ($node->comment != COMMENT_NODE_OPEN) {
       drupal_set_message(t("This discussion is closed: you can't post new comments."), 'error');
-      return new RedirectResponse(url("node/$node->nid", array('absolute' => TRUE)));
+      drupal_goto("node/$node->nid");
     }
     elseif (user_access('post comments')) {
       $build['comment_form'] = comment_add($node, $pid);
     }
     else {
       drupal_set_message(t('You are not authorized to post comments.'), 'error');
-      return new RedirectResponse(url("node/$node->nid", array('absolute' => TRUE)));
+      drupal_goto("node/$node->nid");
     }
   }
 
@@ -121,5 +120,5 @@ function comment_approve(Comment $comment) {
   $comment->save();
 
   drupal_set_message(t('Comment approved.'));
-  return new RedirectResponse('node/' . $comment->nid->target_id, array('absolute' => TRUE));
+  drupal_goto('node/' . $comment->nid->target_id);
 }
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentLanguageTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentLanguageTest.php
index 47efe82..d2d2639 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentLanguageTest.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentLanguageTest.php
@@ -72,8 +72,9 @@ function setUp() {
 
     // Make comment body translatable.
     $field = field_info_field('comment_body');
-    $field['translatable'] = TRUE;
+    $field->translatable = TRUE;
     $field->save();
+
     $this->assertTrue(field_is_translatable('comment', $field), 'Comment body is translatable.');
   }
 
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentTranslationUITest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentTranslationUITest.php
index 2a14791..d09e2b6 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentTranslationUITest.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentTranslationUITest.php
@@ -64,7 +64,7 @@ protected function getTranslatorPermissions() {
   function setupTestFields() {
     parent::setupTestFields();
     $field = field_info_field('comment_body');
-    $field['translatable'] = TRUE;
+    $field->translatable = TRUE;
     $field->save();
   }
 
diff --git a/core/modules/datetime/datetime.module b/core/modules/datetime/datetime.module
index 88e6a77..5f87276 100644
--- a/core/modules/datetime/datetime.module
+++ b/core/modules/datetime/datetime.module
@@ -116,7 +116,7 @@ function datetime_field_info() {
  * Implements hook_field_settings_form().
  */
 function datetime_field_settings_form($field, $instance) {
-  $settings = $field['settings'];
+  $settings = $field->settings;
 
   $form['datetime_type'] = array(
     '#type' => 'select',
@@ -135,7 +135,7 @@ function datetime_field_settings_form($field, $instance) {
  * Implements hook_field_instance_settings_form().
  */
 function datetime_field_instance_settings_form($field, $instance) {
-  $settings = $instance['settings'];
+  $settings = $instance->settings;
 
   $form['default_value'] = array(
     '#type' => 'select',
@@ -239,7 +239,7 @@ function datetime_field_load($entity_type, $entities, $field, $instances, $langc
       $items[$id][$delta]['date'] = NULL;
       $value = isset($item['value']) ? $item['value'] : NULL;
       if (!empty($value)) {
-        $storage_format = $field['settings']['datetime_type'] == 'date' ? DATETIME_DATE_STORAGE_FORMAT: DATETIME_DATETIME_STORAGE_FORMAT;
+        $storage_format = $field->settings['datetime_type'] == 'date' ? DATETIME_DATE_STORAGE_FORMAT: DATETIME_DATETIME_STORAGE_FORMAT;
         $date = new DrupalDateTime($value, DATETIME_STORAGE_TIMEZONE, $storage_format);
         if ($date instanceOf DrupalDateTime && !$date->hasErrors()) {
           $items[$id][$delta]['date'] = $date;
@@ -252,7 +252,7 @@ function datetime_field_load($entity_type, $entities, $field, $instances, $langc
 /**
  * Sets a default value for an empty date field.
  *
- * Callback for $instance['default_value_function'], as implemented by
+ * Callback for $instance->default_value_function, as implemented by
  * Drupal\datetime\Plugin\field\widget\DateTimeDatepicker.
  *
  * @param $entity_type
@@ -273,11 +273,11 @@ function datetime_default_value($entity, $field, $instance, $langcode) {
 
   $value = '';
   $date = '';
-  if ($instance['settings']['default_value'] == 'now') {
+  if ($instance->settings['default_value'] == 'now') {
     // A default value should be in the format and timezone used for date
     // storage.
     $date = new DrupalDateTime('now', DATETIME_STORAGE_TIMEZONE);
-    $storage_format = $field['settings']['datetime_type'] == 'date' ? DATETIME_DATE_STORAGE_FORMAT: DATETIME_DATETIME_STORAGE_FORMAT;
+    $storage_format = $field->settings['datetime_type'] == 'date' ? DATETIME_DATE_STORAGE_FORMAT: DATETIME_DATETIME_STORAGE_FORMAT;
     $value = $date->format($storage_format);
   }
 
diff --git a/core/modules/datetime/lib/Drupal/datetime/Tests/DatetimeFieldTest.php b/core/modules/datetime/lib/Drupal/datetime/Tests/DatetimeFieldTest.php
index a0538d7..e01aff1 100644
--- a/core/modules/datetime/lib/Drupal/datetime/Tests/DatetimeFieldTest.php
+++ b/core/modules/datetime/lib/Drupal/datetime/Tests/DatetimeFieldTest.php
@@ -162,7 +162,7 @@ function testDateField() {
   function testDatetimeField() {
     $field_name = $this->field->id();
     // Change the field to a datetime field.
-    $this->field['settings']['datetime_type'] = 'datetime';
+    $this->field->settings['datetime_type'] = 'datetime';
     $this->field->save();
 
     // Display creation form.
diff --git a/core/modules/edit/lib/Drupal/edit/Form/EditFieldForm.php b/core/modules/edit/lib/Drupal/edit/Form/EditFieldForm.php
index c075b4c..7d52ae0 100644
--- a/core/modules/edit/lib/Drupal/edit/Form/EditFieldForm.php
+++ b/core/modules/edit/lib/Drupal/edit/Form/EditFieldForm.php
@@ -106,7 +106,7 @@ protected function buildEntity(array $form, array &$form_state) {
     //   types: http://drupal.org/node/1678002.
     if ($entity->entityType() == 'node' && $entity->isNewRevision() && !isset($entity->log)) {
       $instance = field_info_instance($entity->entityType(), $form_state['field_name'], $entity->bundle());
-      $entity->log = t('Updated the %field-name field through in-place editing.', array('%field-name' => $instance['label']));
+      $entity->log = t('Updated the %field-name field through in-place editing.', array('%field-name' => $instance->label()));
     }
 
     return $entity;
diff --git a/core/modules/edit/lib/Drupal/edit/MetadataGenerator.php b/core/modules/edit/lib/Drupal/edit/MetadataGenerator.php
index cecc676..e6c77c5 100644
--- a/core/modules/edit/lib/Drupal/edit/MetadataGenerator.php
+++ b/core/modules/edit/lib/Drupal/edit/MetadataGenerator.php
@@ -59,7 +59,7 @@ public function __construct(EditEntityFieldAccessCheckInterface $access_checker,
    * Implements \Drupal\edit\MetadataGeneratorInterface::generate().
    */
   public function generate(EntityInterface $entity, FieldInstance $instance, $langcode, $view_mode) {
-    $field_name = $instance['field_name'];
+    $field_name = $instance->getFieldName();
 
     // Early-return if user does not have access.
     $access = $this->accessChecker->accessEditEntityField($entity, $field_name);
@@ -68,7 +68,7 @@ public function generate(EntityInterface $entity, FieldInstance $instance, $lang
     }
 
     // Early-return if no editor is available.
-    $formatter_id = entity_get_render_display($entity, $view_mode)->getFormatter($instance['field_name'])->getPluginId();
+    $formatter_id = entity_get_render_display($entity, $view_mode)->getFormatter($instance->getFieldName())->getPluginId();
     $items = $entity->getTranslation($langcode, FALSE)->get($field_name)->getValue();
     $editor_id = $this->editorSelector->getEditor($formatter_id, $instance, $items);
     if (!isset($editor_id)) {
@@ -76,7 +76,7 @@ public function generate(EntityInterface $entity, FieldInstance $instance, $lang
     }
 
     // Gather metadata, allow the editor to add additional metadata of its own.
-    $label = $instance['label'];
+    $label = $instance->label();
     $editor = $this->editorManager->createInstance($editor_id);
     $metadata = array(
       'label' => check_plain($label),
diff --git a/core/modules/edit/lib/Drupal/edit/Plugin/InPlaceEditor/DirectEditor.php b/core/modules/edit/lib/Drupal/edit/Plugin/InPlaceEditor/DirectEditor.php
index 39176d1..82f5be3 100644
--- a/core/modules/edit/lib/Drupal/edit/Plugin/InPlaceEditor/DirectEditor.php
+++ b/core/modules/edit/lib/Drupal/edit/Plugin/InPlaceEditor/DirectEditor.php
@@ -27,14 +27,14 @@ class DirectEditor extends EditorBase {
    *   how to generalize to other textual field types.
    */
   function isCompatible(FieldInstance $instance, array $items) {
-    $field = field_info_field($instance['field_name']);
+    $field = field_info_field($instance->getFieldName());
 
     // This editor is incompatible with multivalued fields.
-    if ($field['cardinality'] != 1) {
+    if ($field->cardinality != 1) {
       return FALSE;
     }
     // This editor is incompatible with processed ("rich") text fields.
-    elseif (!empty($instance['settings']['text_processing'])) {
+    elseif (!empty($instance->settings['text_processing'])) {
       return FALSE;
     }
     else {
diff --git a/core/modules/edit/tests/modules/lib/Drupal/edit_test/Plugin/InPlaceEditor/WysiwygEditor.php b/core/modules/edit/tests/modules/lib/Drupal/edit_test/Plugin/InPlaceEditor/WysiwygEditor.php
index 59fe895..44a777d 100644
--- a/core/modules/edit/tests/modules/lib/Drupal/edit_test/Plugin/InPlaceEditor/WysiwygEditor.php
+++ b/core/modules/edit/tests/modules/lib/Drupal/edit_test/Plugin/InPlaceEditor/WysiwygEditor.php
@@ -25,16 +25,16 @@ class WysiwygEditor extends EditorBase {
    * Implements \Drupal\edit\EditPluginInterface::isCompatible().
    */
   function isCompatible(FieldInstance $instance, array $items) {
-    $field = field_info_field($instance['field_name']);
+    $field = field_info_field($instance->getFieldName());
 
     // This editor is incompatible with multivalued fields.
-    if ($field['cardinality'] != 1) {
+    if ($field->cardinality != 1) {
       return FALSE;
     }
     // This editor is compatible with processed ("rich") text fields; but only
     // if there is a currently active text format and that text format is the
     // 'full_html' text format.
-    elseif (!empty($instance['settings']['text_processing'])) {
+    elseif (!empty($instance->settings['text_processing'])) {
       $format_id = $items[0]['format'];
       if (isset($format_id) && $format_id === 'full_html') {
         return TRUE;
diff --git a/core/modules/editor/lib/Drupal/editor/Plugin/InPlaceEditor/Editor.php b/core/modules/editor/lib/Drupal/editor/Plugin/InPlaceEditor/Editor.php
index 7c281c0..9bbcc51 100644
--- a/core/modules/editor/lib/Drupal/editor/Plugin/InPlaceEditor/Editor.php
+++ b/core/modules/editor/lib/Drupal/editor/Plugin/InPlaceEditor/Editor.php
@@ -27,16 +27,16 @@ class Editor extends PluginBase implements EditPluginInterface {
    * Implements \Drupal\edit\Plugin\EditPluginInterface::isCompatible().
    */
   function isCompatible(FieldInstance $instance, array $items) {
-    $field = field_info_field($instance['field_name']);
+    $field = field_info_field($instance->getFieldName());
 
     // This editor is incompatible with multivalued fields.
-    if ($field['cardinality'] != 1) {
+    if ($field->cardinality != 1) {
       return FALSE;
     }
     // This editor is compatible with processed ("rich") text fields; but only
     // if there is a currently active text format, that text format has an
     // associated editor and that editor supports inline editing.
-    elseif (!empty($instance['settings']['text_processing'])) {
+    elseif (!empty($instance->settings['text_processing'])) {
       $format_id = $items[0]['format'];
       if (isset($format_id) && $editor = editor_load($format_id)) {
         $definition = \Drupal::service('plugin.manager.editor')->getDefinition($editor->editor);
diff --git a/core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php b/core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php
index 0a7ff40..a93a091 100644
--- a/core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php
+++ b/core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php
@@ -220,8 +220,8 @@ public function setComponent($name, array $options = array()) {
     }
 
     if ($instance = field_info_instance($this->targetEntityType, $name, $this->bundle)) {
-      $field = field_info_field($instance['field_name']);
-      $options = $this->pluginManager->prepareConfiguration($field['type'], $options);
+      $field = field_info_field($instance->getFieldName());
+      $options = $this->pluginManager->prepareConfiguration($field->type, $options);
 
       // Clear the persisted plugin, if any.
       unset($this->plugins[$name]);
diff --git a/core/modules/entity_reference/entity_reference.install b/core/modules/entity_reference/entity_reference.install
index c40d3ea..eee8613 100644
--- a/core/modules/entity_reference/entity_reference.install
+++ b/core/modules/entity_reference/entity_reference.install
@@ -32,8 +32,8 @@ function entity_reference_field_schema($field) {
 
   // Create a foreign key to the target entity type base type.
   $entity_manager = Drupal::service('plugin.manager.entity');
-  if (is_subclass_of($entity_manager->getControllerClass($field['settings']['target_type'], 'storage'), 'Drupal\Core\Entity\DatabaseStorageController')) {
-    $entity_info = $entity_manager->getDefinition($field['settings']['target_type']);
+  if (is_subclass_of($entity_manager->getControllerClass($field->settings['target_type'], 'storage'), 'Drupal\Core\Entity\DatabaseStorageController')) {
+    $entity_info = $entity_manager->getDefinition($field->settings['target_type']);
 
     $base_table = $entity_info['base_table'];
     $id_column = $entity_info['entity_keys']['id'];
diff --git a/core/modules/entity_reference/entity_reference.module b/core/modules/entity_reference/entity_reference.module
index 84d4743..4d60243 100644
--- a/core/modules/entity_reference/entity_reference.module
+++ b/core/modules/entity_reference/entity_reference.module
@@ -51,14 +51,14 @@ function entity_reference_entity_field_info_alter(&$info, $entity_type) {
   foreach (field_info_instances($entity_type) as $bundle_name => $instances) {
     foreach ($instances as $field_name => $instance) {
       $field = field_info_field($field_name);
-      if ($field['type'] != 'entity_reference') {
+      if ($field->type != 'entity_reference') {
         continue;
       }
       if (isset($info['definitions'][$field_name])) {
-        $info['definitions'][$field_name]['settings']['target_type'] = $field['settings']['target_type'];
+        $info['definitions'][$field_name]['settings']['target_type'] = $field->settings['target_type'];
       }
       elseif (isset($info['optional'][$field_name])) {
-        $info['optional'][$field_name]['settings']['target_type'] = $field['settings']['target_type'];
+        $info['optional'][$field_name]['settings']['target_type'] = $field->settings['target_type'];
       }
     }
   }
@@ -131,9 +131,9 @@ function entity_reference_field_validate(EntityInterface $entity = NULL, $field,
     $invalid_entities = array_diff_key($ids, array_flip($valid_ids));
     if ($invalid_entities) {
       foreach ($invalid_entities as $id => $delta) {
-        $errors[$field['field_name']][$langcode][$delta][] = array(
+        $errors[$field->id()][$langcode][$delta][] = array(
           'error' => 'entity_reference_invalid_entity',
-          'message' => t('The referenced entity (@type: @id) does not exist.', array('@type' => $field['settings']['target_type'], '@id' => $id)),
+          'message' => t('The referenced entity (@type: @id) does not exist.', array('@type' => $field->settings['target_type'], '@id' => $id)),
         );
       }
     }
@@ -159,7 +159,7 @@ function entity_reference_field_settings_form($field, $instance) {
     '#type' => 'select',
     '#title' => t('Type of item to reference'),
     '#options' => $entity_type_options,
-    '#default_value' => $field['settings']['target_type'],
+    '#default_value' => $field->settings['target_type'],
     '#required' => TRUE,
     '#disabled' => $field->hasData(),
     '#size' => 1,
@@ -174,24 +174,24 @@ function entity_reference_field_settings_form($field, $instance) {
  * Reset the instance handler settings, when the target type is changed.
  */
 function entity_reference_field_update_field($field, $prior_field) {
-  if ($field['type'] != 'entity_reference') {
+  if ($field->type != 'entity_reference') {
     // Not an entity reference field.
     return;
   }
 
-  if ($field['settings']['target_type'] == $prior_field['settings']['target_type']) {
+  if ($field->settings['target_type'] == $prior_field->settings['target_type']) {
     // Target type didn't change.
     return;
   }
 
-  if (empty($field['bundles'])) {
+  if ($field->getBundles() == array()) {
     // Field has no instances.
     return;
   }
 
-  $field_name = $field['field_name'];
+  $field_name = $field->id();
 
-  foreach ($field['bundles'] as $entity_type => $bundles) {
+  foreach ($field->getBundles() as $entity_type => $bundles) {
     foreach ($bundles as $bundle) {
       $instance = field_info_instance($entity_type, $field_name, $bundle);
       $instance->settings['handler_settings'] = array();
@@ -207,11 +207,11 @@ function entity_reference_field_instance_settings_form($field, $instance, $form_
   $field = isset($form_state['entity_reference']['field']) ? $form_state['entity_reference']['field'] : $field;
   $instance = isset($form_state['entity_reference']['instance']) ? $form_state['entity_reference']['instance'] : $instance;
 
-  $settings = $instance['settings'];
+  $settings = $instance->settings;
   $settings += array('handler' => 'default');
 
   // Get all selection plugins for this entity type.
-  $selection_plugins = Drupal::service('plugin.manager.entity_reference.selection')->getSelectionGroups($field['settings']['target_type']);
+  $selection_plugins = Drupal::service('plugin.manager.entity_reference.selection')->getSelectionGroups($field->settings['target_type']);
   $handler_groups = array_keys($selection_plugins);
 
   $handlers = Drupal::service('plugin.manager.entity_reference.selection')->getDefinitions();
@@ -334,7 +334,7 @@ function _entity_reference_element_validate_filter(&$element, &$form_state) {
 function _entity_reference_field_instance_settings_validate($form, &$form_state) {
   $instance = $form['#instance'];
   if (isset($form_state['values']['instance'])) {
-    $instance['settings'] = $form_state['values']['instance']['settings'];
+    $instance->settings = $form_state['values']['instance']['settings'];
   }
   $form_state['entity_reference']['instance'] = $instance;
 
diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceAutocomplete.php b/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceAutocomplete.php
index 6a42b57..14f89e9 100644
--- a/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceAutocomplete.php
+++ b/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceAutocomplete.php
@@ -60,7 +60,7 @@ public function __construct(EntityManager $entity_manager) {
    * @see \Drupal\entity_reference\EntityReferenceController
    */
   public function getMatches($field, $instance, $entity_type, $entity_id = '', $prefix = '', $string = '') {
-    $target_type = $field['settings']['target_type'];
+    $target_type = $field->settings['target_type'];
     $matches = array();
     $entity = NULL;
 
@@ -75,7 +75,7 @@ public function getMatches($field, $instance, $entity_type, $entity_id = '', $pr
 
     if (isset($string)) {
       // Get an array of matching entities.
-      $widget = entity_get_form_display($instance['entity_type'], $instance['bundle'], 'default')->getComponent($instance['field_name']);
+      $widget = entity_get_form_display($instance->entity_type, $instance->bundle, 'default')->getComponent($instance->getFieldName());
       $match_operator = !empty($widget['settings']['match_operator']) ? $widget['settings']['match_operator'] : 'CONTAINS';
       $entity_labels = $handler->getReferencableEntities($string, $match_operator, 10);
 
diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceController.php b/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceController.php
index b6099f1..252e301 100644
--- a/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceController.php
+++ b/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceController.php
@@ -77,7 +77,7 @@ public function handleAutocomplete(Request $request, $type, $field_name, $entity
       throw new AccessDeniedHttpException();
     }
 
-    if ($field['type'] != 'entity_reference' || !field_access('edit', $field, $entity_type)) {
+    if ($field->type != 'entity_reference' || !field_access('edit', $field, $entity_type)) {
       throw new AccessDeniedHttpException();
     }
 
diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/entity_reference/selection/SelectionBase.php b/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/entity_reference/selection/SelectionBase.php
index 97aeb6e..b306475 100644
--- a/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/entity_reference/selection/SelectionBase.php
+++ b/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/entity_reference/selection/SelectionBase.php
@@ -56,14 +56,14 @@ public function __construct(FieldDefinitionInterface $field_definition, EntityIn
    * Implements SelectionInterface::settingsForm().
    */
   public static function settingsForm(&$field, &$instance) {
-    $entity_info = entity_get_info($field['settings']['target_type']);
-    $bundles = entity_get_bundles($field['settings']['target_type']);
+    $entity_info = entity_get_info($field->settings['target_type']);
+    $bundles = entity_get_bundles($field->settings['target_type']);
 
     // Merge-in default values.
-    if (!isset($instance['settings']['handler_settings'])) {
-      $instance['settings']['handler_settings'] = array();
+    if (!isset($instance->settings['handler_settings'])) {
+      $instance->settings['handler_settings'] = array();
     }
-    $instance['settings']['handler_settings'] += array(
+    $instance->settings['handler_settings'] += array(
       'target_bundles' => array(),
       'sort' => array(
         'field' => '_none',
@@ -79,10 +79,10 @@ public static function settingsForm(&$field, &$instance) {
 
       $target_bundles_title = t('Bundles');
       // Default core entity types with sensible labels.
-      if ($field['settings']['target_type'] == 'node') {
+      if ($field->settings['target_type'] == 'node') {
         $target_bundles_title = t('Content types');
       }
-      elseif ($field['settings']['target_type'] == 'taxonomy_term') {
+      elseif ($field->settings['target_type'] == 'taxonomy_term') {
         $target_bundles_title = t('Vocabularies');
       }
 
@@ -90,7 +90,7 @@ public static function settingsForm(&$field, &$instance) {
         '#type' => 'checkboxes',
         '#title' => $target_bundles_title,
         '#options' => $bundle_options,
-        '#default_value' => (!empty($instance['settings']['handler_settings']['target_bundles'])) ? $instance['settings']['handler_settings']['target_bundles'] : array(),
+        '#default_value' => (!empty($instance->settings['handler_settings']['target_bundles'])) ? $instance->settings['handler_settings']['target_bundles'] : array(),
         '#required' => TRUE,
         '#size' => 6,
         '#multiple' => TRUE,
@@ -107,7 +107,7 @@ public static function settingsForm(&$field, &$instance) {
     // @todo Use Entity::getPropertyDefinitions() when all entity types are
     // converted to the new Field API.
     $fields = drupal_map_assoc(drupal_schema_fields_sql($entity_info['base_table']));
-    foreach (field_info_instances($field['settings']['target_type']) as $bundle_instances) {
+    foreach (field_info_instances($field->settings['target_type']) as $bundle_instances) {
       foreach ($bundle_instances as $instance_name => $instance_info) {
         $field_info = field_info_field($instance_name);
         foreach ($field_info['columns'] as $column_name => $column_info) {
@@ -124,7 +124,7 @@ public static function settingsForm(&$field, &$instance) {
       ) + $fields,
       '#ajax' => TRUE,
       '#limit_validation_errors' => array(),
-      '#default_value' => $instance['settings']['handler_settings']['sort']['field'],
+      '#default_value' => $instance->settings['handler_settings']['sort']['field'],
     );
 
     $form['sort']['settings'] = array(
@@ -133,9 +133,9 @@ public static function settingsForm(&$field, &$instance) {
       '#process' => array('_entity_reference_form_process_merge_parent'),
     );
 
-    if ($instance['settings']['handler_settings']['sort']['field'] != '_none') {
+    if ($instance->settings['handler_settings']['sort']['field'] != '_none') {
       // Merge-in default values.
-      $instance['settings']['handler_settings']['sort'] += array(
+      $instance->settings['handler_settings']['sort'] += array(
         'direction' => 'ASC',
       );
 
@@ -147,7 +147,7 @@ public static function settingsForm(&$field, &$instance) {
           'ASC' => t('Ascending'),
           'DESC' => t('Descending'),
         ),
-        '#default_value' => $instance['settings']['handler_settings']['sort']['direction'],
+        '#default_value' => $instance->settings['handler_settings']['sort']['direction'],
       );
     }
 
@@ -261,8 +261,8 @@ public function buildEntityQuery($match = NULL, $match_operator = 'CONTAINS') {
     $entity_info = entity_get_info($target_type);
 
     $query = \Drupal::entityQuery($target_type);
-    if (!empty($this->instance['settings']['handler_settings']['target_bundles'])) {
-      $query->condition($entity_info['entity_keys']['bundle'], $this->instance['settings']['handler_settings']['target_bundles'], 'IN');
+    if (!empty($this->instance->settings['handler_settings']['target_bundles'])) {
+      $query->condition($entity_info['entity_keys']['bundle'], $this->instance->settings['handler_settings']['target_bundles'], 'IN');
     }
 
     if (isset($match) && isset($entity_info['entity_keys']['label'])) {
diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/field/formatter/EntityReferenceFormatterBase.php b/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/field/formatter/EntityReferenceFormatterBase.php
index 51f5285..5c4a252 100644
--- a/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/field/formatter/EntityReferenceFormatterBase.php
+++ b/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/field/formatter/EntityReferenceFormatterBase.php
@@ -40,7 +40,7 @@ public function prepareView(array $entities, $langcode, array &$items) {
       }
     }
 
-    $target_type = $this->field['settings']['target_type'];
+    $target_type = $this->field->settings['target_type'];
 
     $target_entities = array();
 
diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceItemTest.php b/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceItemTest.php
index 8c17fd6..4539f13 100644
--- a/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceItemTest.php
+++ b/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceItemTest.php
@@ -119,7 +119,7 @@ public function testEntityReferenceFieldSchema() {
     $this->assertEqual(count($schema['foreign keys']), 1, 'There is 1 foreign key in the schema.');
 
     $foreign_key = reset($schema['foreign keys']);
-    $foreign_key_column = _field_sql_storage_columnname($field['field_name'], $foreign_key_column_name);
+    $foreign_key_column = _field_sql_storage_columnname($field->id(), $foreign_key_column_name);
     $this->assertEqual($foreign_key['table'], 'taxonomy_term_data', 'Foreign key table name preserved in the schema.');
     $this->assertEqual($foreign_key['columns'][$foreign_key_column], 'tid', 'Foreign key column name preserved in the schema.');
 
diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceSelectionSortTest.php b/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceSelectionSortTest.php
index 09dd2c8..6592f27 100644
--- a/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceSelectionSortTest.php
+++ b/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceSelectionSortTest.php
@@ -133,7 +133,7 @@ public function testSort() {
     $this->assertIdentical($result['article'], $expected_result, 'Query sorted by field returned expected values.');
 
     // Assert sort by property.
-    $instance['settings']['handler_settings']['sort'] = array(
+    $instance->settings['handler_settings']['sort'] = array(
       'field' => 'nid',
       'direction' => 'ASC',
     );
diff --git a/core/modules/field/field.api.php b/core/modules/field/field.api.php
index 3535b00..e8256ea 100644
--- a/core/modules/field/field.api.php
+++ b/core/modules/field/field.api.php
@@ -237,7 +237,7 @@ function hook_field_info_alter(&$info) {
  *     as related, only existing SQL tables, such as {taxonomy_term_data}.
  */
 function hook_field_schema($field) {
-  if ($field['type'] == 'text_long') {
+  if ($field->type == 'text_long') {
     $columns = array(
       'value' => array(
         'type' => 'text',
@@ -250,7 +250,7 @@ function hook_field_schema($field) {
     $columns = array(
       'value' => array(
         'type' => 'varchar',
-        'length' => $field['settings']['max_length'],
+        'length' => $field->settings['max_length'],
         'not null' => FALSE,
       ),
     );
@@ -320,7 +320,7 @@ function hook_field_load($entity_type, $entities, $field, $instances, $langcode,
       // by formatters if needed.
       if (empty($instances[$id]['settings']['text_processing']) || filter_format_allowcache($item['format'])) {
         $items[$id][$delta]['safe_value'] = isset($item['value']) ? text_sanitize($instances[$id]['settings']['text_processing'], $langcode, $item, 'value') : '';
-        if ($field['type'] == 'text_with_summary') {
+        if ($field->type == 'text_with_summary') {
           $items[$id][$delta]['safe_summary'] = isset($item['summary']) ? text_sanitize($instances[$id]['settings']['text_processing'], $langcode, $item, 'summary') : '';
         }
       }
@@ -355,14 +355,14 @@ function hook_field_load($entity_type, $entities, $field, $instances, $langcode,
  * @param $langcode
  *   The language associated with $items.
  * @param $items
- *   $entity->{$field['field_name']}, or an empty array if unset.
+ *   $entity->{$field->id()}, or an empty array if unset.
  */
 function hook_field_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items) {
   // Sample code from image.module: if there are no images specified at all,
   // use the default image.
   foreach ($entities as $id => $entity) {
-    if (empty($items[$id]) && $field['settings']['default_image']) {
-      if ($file = file_load($field['settings']['default_image'])) {
+    if (empty($items[$id]) && $field->settings['default_image']) {
+      if ($file = file_load($field->settings['default_image'])) {
         $items[$id][0] = (array) $file + array(
           'is_default' => TRUE,
           'alt' => '',
@@ -388,7 +388,7 @@ function hook_field_prepare_view($entity_type, $entities, $field, $instances, $l
  * @param $langcode
  *   The language associated with $items.
  * @param $items
- *   $entity->{$field['field_name']}[$langcode], or an empty array if unset.
+ *   $entity->{$field->id()}[$langcode], or an empty array if unset.
  * @param $errors
  *   The array of errors (keyed by field name, language code, and delta) that
  *   have already been reported for the entity. The function should add its
@@ -400,10 +400,10 @@ function hook_field_prepare_view($entity_type, $entities, $field, $instances, $l
 function hook_field_validate(\Drupal\Core\Entity\EntityInterface $entity = NULL, $field, $instance, $langcode, $items, &$errors) {
   foreach ($items as $delta => $item) {
     if (!empty($item['value'])) {
-      if (!empty($field['settings']['max_length']) && drupal_strlen($item['value']) > $field['settings']['max_length']) {
-        $errors[$field['field_name']][$langcode][$delta][] = array(
+      if (!empty($field->settings['max_length']) && drupal_strlen($item['value']) > $field->settings['max_length']) {
+        $errors[$field->id()][$langcode][$delta][] = array(
           'error' => 'text_max_length',
-          'message' => t('%name: the value may not be longer than %max characters.', array('%name' => $instance['label'], '%max' => $field['settings']['max_length'])),
+          'message' => t('%name: the value may not be longer than %max characters.', array('%name' => $instance->label(), '%max' => $field->settings['max_length'])),
         );
       }
     }
@@ -425,15 +425,15 @@ function hook_field_validate(\Drupal\Core\Entity\EntityInterface $entity = NULL,
  * @param $langcode
  *   The language associated with $items.
  * @param $items
- *   $entity->{$field['field_name']}[$langcode], or an empty array if unset.
+ *   $entity->{$field->id()}[$langcode], or an empty array if unset.
  */
 function hook_field_presave(\Drupal\Core\Entity\EntityInterface $entity, $field, $instance, $langcode, &$items) {
-  if ($field['type'] == 'number_decimal') {
+  if ($field->type == 'number_decimal') {
     // Let PHP round the value to ensure consistent behavior across storage
     // backends.
     foreach ($items as $delta => $item) {
       if (isset($item['value'])) {
-        $items[$delta]['value'] = round($item['value'], $field['settings']['scale']);
+        $items[$delta]['value'] = round($item['value'], $field->settings['scale']);
       }
     }
   }
@@ -458,13 +458,13 @@ function hook_field_presave(\Drupal\Core\Entity\EntityInterface $entity, $field,
  * @param $langcode
  *   The language associated with $items.
  * @param $items
- *   $entity->{$field['field_name']}[$langcode], or an empty array if unset.
+ *   $entity->{$field->id()}[$langcode], or an empty array if unset.
  *
  * @see hook_field_update()
  * @see hook_field_delete()
  */
 function hook_field_insert(\Drupal\Core\Entity\EntityInterface $entity, $field, $instance, $langcode, &$items) {
-  if (config('taxonomy.settings')->get('maintain_index_table') && $field['storage']['type'] == 'field_sql_storage' && $entity->entityType() == 'node' && $entity->status) {
+  if (config('taxonomy.settings')->get('maintain_index_table') && $field->storage['type'] == 'field_sql_storage' && $entity->entityType() == 'node' && $entity->status) {
     $query = db_insert('taxonomy_index')->fields(array('nid', 'tid', 'sticky', 'created', ));
     foreach ($items as $item) {
       $query->values(array(
@@ -497,13 +497,13 @@ function hook_field_insert(\Drupal\Core\Entity\EntityInterface $entity, $field,
  * @param $langcode
  *   The language associated with $items.
  * @param $items
- *   $entity->{$field['field_name']}[$langcode], or an empty array if unset.
+ *   $entity->{$field->id()}[$langcode], or an empty array if unset.
  *
  * @see hook_field_insert()
  * @see hook_field_delete()
  */
 function hook_field_update(\Drupal\Core\Entity\EntityInterface $entity, $field, $instance, $langcode, &$items) {
-  if (config('taxonomy.settings')->get('maintain_index_table') && $field['storage']['type'] == 'field_sql_storage' && $entity->entityType() == 'node') {
+  if (config('taxonomy.settings')->get('maintain_index_table') && $field->storage['type'] == 'field_sql_storage' && $entity->entityType() == 'node') {
     $first_call = &drupal_static(__FUNCTION__, array());
 
     // We don't maintain data for old revisions, so clear all previous values
@@ -581,7 +581,7 @@ function hook_field_storage_update_field($field, $prior_field) {
  * @param $langcode
  *   The language associated with $items.
  * @param $items
- *   $entity->{$field['field_name']}[$langcode], or an empty array if unset.
+ *   $entity->{$field->id()}[$langcode], or an empty array if unset.
  *
  * @see hook_field_insert()
  * @see hook_field_update()
@@ -609,7 +609,7 @@ function hook_field_delete(\Drupal\Core\Entity\EntityInterface $entity, $field,
  * @param $langcode
  *   The language associated with $items.
  * @param $items
- *   $entity->{$field['field_name']}[$langcode], or an empty array if unset.
+ *   $entity->{$field->id()}[$langcode], or an empty array if unset.
  */
 function hook_field_delete_revision(\Drupal\Core\Entity\EntityInterface $entity, $field, $instance, $langcode, &$items) {
   foreach ($items as $delta => $item) {
@@ -630,7 +630,7 @@ function hook_field_delete_revision(\Drupal\Core\Entity\EntityInterface $entity,
  * @param $langcode
  *   The language associated with $items.
  * @param $items
- *   $entity->{$field['field_name']}[$langcode], or an empty array if unset.
+ *   $entity->{$field->id()}[$langcode], or an empty array if unset.
  * @param $source_entity
  *   The source entity from which field values are being copied.
  * @param $source_langcode
@@ -639,7 +639,7 @@ function hook_field_delete_revision(\Drupal\Core\Entity\EntityInterface $entity,
 function hook_field_prepare_translation(\Drupal\Core\Entity\EntityInterface $entity, $field, $instance, $langcode, &$items, $source_entity, $source_langcode) {
   // If the translating user is not permitted to use the assigned text format,
   // we must not expose the source values.
-  $field_name = $field['field_name'];
+  $field_name = $field->id();
   $formats = filter_formats();
   $format_id = $source_entity->{$field_name}[$source_langcode][0]['format'];
   if (!filter_access($formats[$format_id])) {
@@ -1196,8 +1196,8 @@ function hook_field_storage_details($field) {
   $details = array();
 
   // Add field columns.
-  foreach ((array) $field['columns'] as $column_name => $attributes) {
-    $real_name = _field_sql_storage_columnname($field['field_name'], $column_name);
+  foreach ((array) $field->getSchema('columns') as $column_name => $attributes) {
+    $real_name = _field_sql_storage_columnname($field->id(), $column_name);
     $columns[$column_name] = $real_name;
   }
   return array(
@@ -1224,9 +1224,9 @@ function hook_field_storage_details($field) {
  * @see hook_field_storage_details()
  */
 function hook_field_storage_details_alter(&$details, $field) {
-  if ($field['field_name'] == 'field_of_interest') {
+  if ($field->id() == 'field_of_interest') {
     $columns = array();
-    foreach ((array) $field['columns'] as $column_name => $attributes) {
+    foreach ((array) $field->getSchema('columns') as $column_name => $attributes) {
       $columns[$column_name] = $column_name;
     }
     $details['drupal_variables'] = array(
@@ -1274,7 +1274,7 @@ function hook_field_storage_load($entity_type, $entities, $age, $fields, $option
     // on each field individually is more efficient than loading all fields in
     // memory upfront with field_info_field_by_ids().
     $field = field_info_field_by_id($field_id);
-    $field_name = $field['field_name'];
+    $field_name = $field->id();
     $table = $load_current ? _field_sql_storage_tablename($field) : _field_sql_storage_revision_tablename($field);
 
     $query = db_select($table, 't')
@@ -1296,11 +1296,11 @@ function hook_field_storage_load($entity_type, $entities, $age, $fields, $option
         $delta_count[$row->entity_id][$row->langcode] = 0;
       }
 
-      if ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED || $delta_count[$row->entity_id][$row->langcode] < $field['cardinality']) {
+      if ($field->cardinality == FIELD_CARDINALITY_UNLIMITED || $delta_count[$row->entity_id][$row->langcode] < $field->cardinality) {
         $item = array();
         // For each column declared by the field, populate the item
         // from the prefixed database column.
-        foreach ($field['columns'] as $column => $attributes) {
+        foreach ($field->getSchema('columns') as $column => $attributes) {
           $column_name = _field_sql_storage_columnname($field_name, $column);
           $item[$column] = $row->$column_name;
         }
@@ -1338,7 +1338,7 @@ function hook_field_storage_write(\Drupal\Core\Entity\EntityInterface $entity, $
 
   foreach ($fields as $field_id) {
     $field = field_info_field_by_id($field_id);
-    $field_name = $field['field_name'];
+    $field_name = $field->id();
     $table_name = _field_sql_storage_tablename($field);
     $revision_name = _field_sql_storage_revision_tablename($field);
 
@@ -1368,7 +1368,7 @@ function hook_field_storage_write(\Drupal\Core\Entity\EntityInterface $entity, $
     // Prepare the multi-insert query.
     $do_insert = FALSE;
     $columns = array('entity_type', 'entity_id', 'revision_id', 'bundle', 'delta', 'langcode');
-    foreach ($field['columns'] as $column => $attributes) {
+    foreach ($field->getSchema('columns') as $column => $attributes) {
       $columns[] = _field_sql_storage_columnname($field_name, $column);
     }
     $query = db_insert($table_name)->fields($columns);
@@ -1388,7 +1388,7 @@ function hook_field_storage_write(\Drupal\Core\Entity\EntityInterface $entity, $
           'delta' => $delta,
           'langcode' => $langcode,
         );
-        foreach ($field['columns'] as $column => $attributes) {
+        foreach ($field->getSchema('columns') as $column => $attributes) {
           $record[_field_sql_storage_columnname($field_name, $column)] = isset($item[$column]) ? $item[$column] : NULL;
         }
         $query->values($record);
@@ -1396,7 +1396,7 @@ function hook_field_storage_write(\Drupal\Core\Entity\EntityInterface $entity, $
           $revision_query->values($record);
         }
 
-        if ($field['cardinality'] != FIELD_CARDINALITY_UNLIMITED && ++$delta_count == $field['cardinality']) {
+        if ($field->cardinality != FIELD_CARDINALITY_UNLIMITED && ++$delta_count == $field->cardinality) {
           break;
         }
       }
@@ -1424,8 +1424,8 @@ function hook_field_storage_write(\Drupal\Core\Entity\EntityInterface $entity, $
  */
 function hook_field_storage_delete(\Drupal\Core\Entity\EntityInterface $entity, $fields) {
   foreach (field_info_instances($entity->entityType(), $entity->bundle()) as $instance) {
-    if (isset($fields[$instance['field_id']])) {
-      $field = field_info_field_by_id($instance['field_id']);
+    if (isset($fields[$instance->field_uuid])) {
+      $field = field_info_field_by_id($instance->field_uuid);
       field_sql_storage_field_storage_purge($entity, $field, $instance);
     }
   }
@@ -1502,7 +1502,7 @@ function hook_field_storage_query($query) {
       $select_query->fields($table_alias, array('entity_type', 'entity_id', 'revision_id', 'bundle'));
       $field_base_table = $table_alias;
     }
-    if ($field['cardinality'] != 1) {
+    if ($field->cardinality != 1) {
       $select_query->distinct();
     }
   }
@@ -1512,7 +1512,7 @@ function hook_field_storage_query($query) {
     $table_alias = $table_aliases[$key];
     $field = $condition['field'];
     // Add the specified condition.
-    $sql_field = "$table_alias." . _field_sql_storage_columnname($field['field_name'], $condition['column']);
+    $sql_field = "$table_alias." . _field_sql_storage_columnname($field->id(), $condition['column']);
     $query->addCondition($select_query, $sql_field, $condition);
     // Add delta / language group conditions.
     foreach (array('delta', 'langcode') as $column) {
@@ -1565,7 +1565,7 @@ function hook_field_storage_query($query) {
       $specifier = $order['specifier'];
       $field = $specifier['field'];
       $table_alias = $table_aliases[$specifier['index']];
-      $sql_field = "$table_alias." . _field_sql_storage_columnname($field['field_name'], $specifier['column']);
+      $sql_field = "$table_alias." . _field_sql_storage_columnname($field->id(), $specifier['column']);
       $select_query->orderBy($sql_field, $order['direction']);
     }
     elseif ($order['type'] == 'property') {
@@ -1605,7 +1605,7 @@ function hook_field_storage_create_field($field) {
  */
 function hook_field_storage_delete_field($field) {
   // Mark all data associated with the field for deletion.
-  $field['deleted'] = FALSE;
+  $field->deleted = FALSE;
   $table = _field_sql_storage_tablename($field);
   $revision_table = _field_sql_storage_revision_tablename($field);
   db_update($table)
@@ -1613,7 +1613,7 @@ function hook_field_storage_delete_field($field) {
     ->execute();
 
   // Move the table to a unique name while the table contents are being deleted.
-  $field['deleted'] = TRUE;
+  $field->deleted = TRUE;
   $new_table = _field_sql_storage_tablename($field);
   $revision_new_table = _field_sql_storage_revision_tablename($field);
   db_rename_table($table, $new_table);
@@ -1632,18 +1632,18 @@ function hook_field_storage_delete_field($field) {
  *   The instance being deleted.
  */
 function hook_field_storage_delete_instance($instance) {
-  $field = field_info_field($instance['field_name']);
+  $field = field_info_field($instance->getFieldName());
   $table_name = _field_sql_storage_tablename($field);
   $revision_name = _field_sql_storage_revision_tablename($field);
   db_update($table_name)
     ->fields(array('deleted' => 1))
-    ->condition('entity_type', $instance['entity_type'])
-    ->condition('bundle', $instance['bundle'])
+    ->condition('entity_type', $instance->entity_type)
+    ->condition('bundle', $instance->bundle)
     ->execute();
   db_update($revision_name)
     ->fields(array('deleted' => 1))
-    ->condition('entity_type', $instance['entity_type'])
-    ->condition('bundle', $instance['bundle'])
+    ->condition('entity_type', $instance->entity_type)
+    ->condition('bundle', $instance->bundle)
     ->execute();
 }
 
@@ -1857,13 +1857,13 @@ function hook_field_update_forbid($field, $prior_field) {
   // the new field will have fewer values, and any data exists for the
   // abandoned keys, the field will have no way to display them. So,
   // forbid such an update.
-  if ($field->hasData() && count($field['settings']['allowed_values']) < count($prior_field['settings']['allowed_values'])) {
+  if ($field->hasData() && count($field->settings['allowed_values']) < count($prior_field->settings['allowed_values'])) {
     // Identify the keys that will be lost.
-    $lost_keys = array_diff(array_keys($field['settings']['allowed_values']), array_keys($prior_field['settings']['allowed_values']));
+    $lost_keys = array_diff(array_keys($field->settings['allowed_values']), array_keys($prior_field->settings['allowed_values']));
     // If any data exist for those keys, forbid the update.
     $query = new EntityFieldQuery();
     $found = $query
-      ->fieldCondition($prior_field['field_name'], 'value', $lost_keys)
+      ->fieldCondition($prior_field->id(), 'value', $lost_keys)
       ->range(0, 1)
       ->execute();
     if ($found) {
@@ -1969,7 +1969,7 @@ function hook_field_read_instance($instance) {
  */
 function hook_field_purge_field($field) {
   db_delete('my_module_field_info')
-    ->condition('id', $field['id'])
+    ->condition('id', $field->id())
     ->execute();
 }
 
@@ -1987,7 +1987,7 @@ function hook_field_purge_field($field) {
  */
 function hook_field_purge_instance($instance) {
   db_delete('my_module_field_instance_info')
-    ->condition('id', $instance['id'])
+    ->condition('id', $instance->id)
     ->execute();
 }
 
@@ -2018,7 +2018,7 @@ function hook_field_storage_purge_field($field) {
  */
 function hook_field_storage_purge_field_instance($instance) {
   db_delete('my_module_field_instance_info')
-    ->condition('id', $instance['id'])
+    ->condition('id', $instance->id)
     ->execute();
 }
 
@@ -2073,7 +2073,7 @@ function hook_field_storage_purge(\Drupal\Core\Entity\EntityInterface $entity, $
  *   TRUE if the operation is allowed, and FALSE if the operation is denied.
  */
 function hook_field_access($op, \Drupal\field\FieldInterface $field, $entity_type, $entity, $account) {
-  if ($field['field_name'] == 'field_of_interest' && $op == 'edit') {
+  if ($field->id() == 'field_of_interest' && $op == 'edit') {
     return user_access('edit field of interest', $account);
   }
   return TRUE;
diff --git a/core/modules/field/field.attach.inc b/core/modules/field/field.attach.inc
index 7965679..f49eeb8 100644
--- a/core/modules/field/field.attach.inc
+++ b/core/modules/field/field.attach.inc
@@ -171,8 +171,8 @@ function field_invoke_method($method, $target_function, EntityInterface $entity,
     $target = call_user_func($target_function, $instance);
 
     if (method_exists($target, $method)) {
-      $field = field_info_field_by_id($instance['field_id']);
-      $field_name = $field['field_name'];
+      $field = field_info_field_by_id($instance->field_uuid);
+      $field_name = $field->id();
 
       // Determine the list of languages to iterate on.
       $available_langcodes = field_available_languages($entity_type, $field);
@@ -266,8 +266,8 @@ function field_invoke_method_multiple($method, $target_function, array $entities
     $entity_instances = _field_invoke_get_instances($entity_type, $entity->bundle(), $options);
 
     foreach ($entity_instances as $instance) {
-      $instance_id = $instance['id'];
-      $field_name = $instance['field_name'];
+      $instance_id = $instance->id;
+      $field_name = $instance->getFieldName();
 
       // Let the closure determine the target object on which the method should
       // be called.
@@ -283,7 +283,7 @@ function field_invoke_method_multiple($method, $target_function, array $entities
 
         // Unless a language code suggestion is provided we iterate on all the
         // available language codes.
-        $field = field_info_field_by_id($instance['field_id']);
+        $field = field_info_field_by_id($instance->field_uuid);
         $available_langcodes = field_available_languages($entity_type, $field);
         $langcode = !empty($options['langcode'][$id]) ? $options['langcode'][$id] : $options['langcode'];
         $langcodes = _field_language_suggestion($available_langcodes, $langcode, $field_name);
@@ -300,7 +300,7 @@ function field_invoke_method_multiple($method, $target_function, array $entities
 
   // For each instance, invoke the method and collect results.
   foreach ($instances as $instance_id => $instance) {
-    $field_name = $instance['field_name'];
+    $field_name = $instance->getFieldName();
 
     // Iterate over all the field translations.
     foreach ($grouped_items[$instance_id] as $langcode => &$items) {
@@ -401,9 +401,9 @@ function _field_invoke($op, EntityInterface $entity, &$a = NULL, &$b = NULL, $op
   foreach ($instances as $instance) {
     // field_info_field() is not available for deleted fields, so use
     // field_info_field_by_id().
-    $field = field_info_field_by_id($instance['field_id']);
-    $field_name = $field['field_name'];
-    $function = $options['default'] ? 'field_default_' . $op : $field['module'] . '_field_' . $op;
+    $field = field_info_field_by_id($instance->field_uuid);
+    $field_name = $field->id();
+    $function = $options['default'] ? 'field_default_' . $op : $field->module . '_field_' . $op;
     if (function_exists($function)) {
       // Determine the list of languages to iterate on.
       $available_langcodes = field_available_languages($entity->entityType(), $field);
@@ -509,10 +509,10 @@ function _field_invoke_multiple($op, $entity_type, $entities, &$a = NULL, &$b =
     $id = $entity->id();
 
     foreach ($instances as $instance) {
-      $field_id = $instance['field_id'];
-      $field_name = $instance['field_name'];
+      $field_id = $instance->field_uuid;
+      $field_name = $instance->getFieldName();
       $field = field_info_field_by_id($field_id);
-      $function = $options['default'] ? 'field_default_' . $op : $field['module'] . '_field_' . $op;
+      $function = $options['default'] ? 'field_default_' . $op : $field->module . '_field_' . $op;
       if (function_exists($function)) {
         // Add the field to the list of fields to invoke the hook on.
         if (!isset($fields[$field_id])) {
@@ -540,8 +540,8 @@ function _field_invoke_multiple($op, $entity_type, $entities, &$a = NULL, &$b =
 
   // For each field, invoke the field hook and collect results.
   foreach ($fields as $field_id => $field) {
-    $field_name = $field['field_name'];
-    $function = $options['default'] ? 'field_default_' . $op : $field['module'] . '_field_' . $op;
+    $field_name = $field->id();
+    $function = $options['default'] ? 'field_default_' . $op : $field->module . '_field_' . $op;
     // Iterate over all the field translations.
     foreach ($grouped_items[$field_id] as $langcode => &$items) {
       $entities = $grouped_entities[$field_id][$langcode];
@@ -671,11 +671,11 @@ function _field_invoke_get_instances($entity_type, $bundle, $options) {
     // Deleted fields are not included in field_info_instances(), and need to
     // be fetched from the database with field_read_instances().
     $params = array('entity_type' => $entity_type, 'bundle' => $bundle);
-    if (isset($options['field_id'])) {
+    if (isset($options->field_uuid)) {
       // Single-field mode by field id: field_read_instances() does the filtering.
       // Single-field mode by field name is not compatible with the 'deleted'
       // option.
-      $params['field_id'] = $options['field_id'];
+      $params->field_uuid = $options->field_uuid;
     }
     $instances = field_read_instances($params, array('include_deleted' => TRUE));
   }
@@ -686,11 +686,11 @@ function _field_invoke_get_instances($entity_type, $bundle, $options) {
   }
   else {
     $instances = field_info_instances($entity_type, $bundle);
-    if (isset($options['field_id'])) {
+    if (isset($options->field_uuid)) {
       // Single-field mode by field id: we need to loop on each instance to
       // find the right one.
       foreach ($instances as $instance) {
-        if ($instance['field_id'] == $options['field_id']) {
+        if ($instance->field_uuid == $options->field_uuid) {
           $instances = array($instance);
           break;
         }
@@ -714,7 +714,7 @@ function _field_invoke_get_instances($entity_type, $bundle, $options) {
  */
 function _field_invoke_widget_target($form_display) {
   return function ($instance) use ($form_display) {
-    return $form_display->getWidget($instance['field_name']);
+    return $form_display->getWidget($instance->getFieldName());
   };
 }
 
@@ -893,7 +893,7 @@ function field_attach_load($entity_type, $entities, $age = FIELD_LOAD_CURRENT, $
   // types can be cached.
   $cache_read = $load_current && $info['field_cache'] && empty($options['deleted']);
   // In addition, do not write to the cache when loading a single field.
-  $cache_write = $cache_read && !isset($options['field_id']);
+  $cache_write = $cache_read && !isset($options->field_uuid);
 
   if (empty($entities)) {
     return;
@@ -954,8 +954,8 @@ function field_attach_load($entity_type, $entities, $age = FIELD_LOAD_CURRENT, $
       $id = $entity->id();
       $vid = $entity->getRevisionId();
       foreach ($instances as $instance) {
-        $field_name = $instance['field_name'];
-        $field_id = $instance['field_id'];
+        $field_name = $instance->getFieldName();
+        $field_id = $instance->field_uuid;
         // Make sure all fields are present at least as empty arrays.
         if (!isset($queried_entities[$id]->{$field_name})) {
           $queried_entities[$id]->{$field_name} = array();
@@ -963,7 +963,7 @@ function field_attach_load($entity_type, $entities, $age = FIELD_LOAD_CURRENT, $
         // Collect the storage backend if the field has not been loaded yet.
         if (!isset($skip_fields[$field_id])) {
           $field = field_info_field_by_id($field_id);
-          $storages[$field['storage']['type']][$field_id][] = $load_current ? $id : $vid;
+          $storages[$field->storage['type']][$field_id][] = $load_current ? $id : $vid;
         }
       }
     }
@@ -988,7 +988,7 @@ function field_attach_load($entity_type, $entities, $age = FIELD_LOAD_CURRENT, $
         $data = array();
         $instances = field_info_instances($entity_type, $entity->bundle());
         foreach ($instances as $instance) {
-          $data[$instance['field_name']] = $queried_entities[$id]->{$instance['field_name']};
+          $data[$instance->getFieldName()] = $queried_entities[$id]->{$instance->getFieldName()};
         }
         $cid = "field:$entity_type:$id";
         cache('field')->set($cid, $data);
@@ -1198,13 +1198,13 @@ function field_attach_insert(EntityInterface $entity) {
   // Collect the storage backends used by the remaining fields in the entities.
   $storages = array();
   foreach (field_info_instances($entity->entityType(), $entity->bundle()) as $instance) {
-    $field = field_info_field_by_id($instance['field_id']);
-    $field_id = $field['uuid'];
-    $field_name = $field['field_name'];
+    $field = field_info_field_by_id($instance->field_uuid);
+    $field_id = $field->uuid;
+    $field_name = $field->id();
     if (!empty($entity->$field_name)) {
       // Collect the storage backend if the field has not been written yet.
       if (!isset($skip_fields[$field_id])) {
-        $storages[$field['storage']['type']][$field_id] = $field_id;
+        $storages[$field->storage['type']][$field_id] = $field_id;
       }
     }
   }
@@ -1242,9 +1242,9 @@ function field_attach_update(EntityInterface $entity) {
   // Collect the storage backends used by the remaining fields in the entities.
   $storages = array();
   foreach (field_info_instances($entity->entityType(), $entity->bundle()) as $instance) {
-    $field = field_info_field_by_id($instance['field_id']);
-    $field_id = $field['uuid'];
-    $field_name = $field['field_name'];
+    $field = field_info_field_by_id($instance->field_uuid);
+    $field_id = $field->uuid;
+    $field_name = $field->id();
     // Leave the field untouched if $entity comes with no $field_name property,
     // but empty the field if it comes as a NULL value or an empty array.
     // Function property_exists() is slower, so we catch the more frequent
@@ -1252,7 +1252,7 @@ function field_attach_update(EntityInterface $entity) {
     if (isset($entity->$field_name) || property_exists($entity, $field_name)) {
       // Collect the storage backend if the field has not been written yet.
       if (!isset($skip_fields[$field_id])) {
-        $storages[$field['storage']['type']][$field_id] = $field_id;
+        $storages[$field->storage['type']][$field_id] = $field_id;
       }
     }
   }
@@ -1288,9 +1288,9 @@ function field_attach_delete(EntityInterface $entity) {
   // Collect the storage backends used by the fields in the entities.
   $storages = array();
   foreach (field_info_instances($entity->entityType(), $entity->bundle()) as $instance) {
-    $field = field_info_field_by_id($instance['field_id']);
-    $field_id = $field['uuid'];
-    $storages[$field['storage']['type']][$field_id] = $field_id;
+    $field = field_info_field_by_id($instance->field_uuid);
+    $field_id = $field->uuid;
+    $storages[$field->storage['type']][$field_id] = $field_id;
   }
 
   // Field storage backends delete their data.
@@ -1324,9 +1324,9 @@ function field_attach_delete_revision(EntityInterface $entity) {
   // Collect the storage backends used by the fields in the entities.
   $storages = array();
   foreach (field_info_instances($entity->entityType(), $entity->bundle()) as $instance) {
-    $field = field_info_field_by_id($instance['field_id']);
-    $field_id = $field['uuid'];
-    $storages[$field['storage']['type']][$field_id] = $field_id;
+    $field = field_info_field_by_id($instance->field_uuid);
+    $field_id = $field->uuid;
+    $storages[$field->storage['type']][$field_id] = $field_id;
   }
 
   // Field storage backends delete their data.
@@ -1397,8 +1397,8 @@ function field_attach_prepare_view($entity_type, array $entities, array $display
   // instance, call the prepareView() method on the formatter object handed by
   // the entity display.
   $target_function = function ($instance) use ($displays) {
-    if (isset($displays[$instance['bundle']])) {
-      return $displays[$instance['bundle']]->getFormatter($instance['field_name']);
+    if (isset($displays[$instance->bundle])) {
+      return $displays[$instance->bundle]->getFormatter($instance->getFieldName());
     }
   };
   field_invoke_method_multiple('prepareView', $target_function, $prepare, $null, $null, $options);
@@ -1440,7 +1440,7 @@ function field_attach_view(EntityInterface $entity, EntityDisplay $display, $lan
   // For each instance, call the view() method on the formatter object handed
   // by the entity display.
   $target_function = function ($instance) use ($display) {
-    return $display->getFormatter($instance['field_name']);
+    return $display->getFormatter($instance->getFieldName());
   };
   $null = NULL;
   $output = field_invoke_method('view', $target_function, $entity, $null, $null, $options);
@@ -1485,7 +1485,7 @@ function field_attach_preprocess(EntityInterface $entity, $element, &$variables)
   // Ensure we are working with a BC mode entity.
   $entity = $entity->getBCEntity();
   foreach (field_info_instances($entity->entityType(), $entity->bundle()) as $instance) {
-    $field_name = $instance['field_name'];
+    $field_name = $instance->getFieldName();
     if (isset($element[$field_name]['#language'])) {
       $langcode = $element[$field_name]['#language'];
       $variables[$field_name] = isset($entity->{$field_name}[$langcode]) ? $entity->{$field_name}[$langcode] : NULL;
@@ -1554,7 +1554,7 @@ function field_entity_bundle_rename($entity_type, $bundle_old, $bundle_new) {
   $instances = field_read_instances();
   foreach ($instances as $instance) {
     if ($instance->entity_type == $entity_type && $instance->bundle == $bundle_old) {
-      $id_new = $instance['entity_type'] . '.' . $bundle_new . '.' . $instance['field_name'];
+      $id_new = $instance->entity_type . '.' . $bundle_new . '.' . $instance->getFieldName();
       $instance->id = $id_new;
       $instance->bundle = $bundle_new;
       $instance->allowBundleRename();
diff --git a/core/modules/field/field.crud.inc b/core/modules/field/field.crud.inc
index bbd0d45..49c46e3 100644
--- a/core/modules/field/field.crud.inc
+++ b/core/modules/field/field.crud.inc
@@ -78,7 +78,7 @@ function field_create_field(array $field) {
  *
  * @param mixed $field
  *   Either the \Drupal\field\Plugin\Core\Entity\Field object to update, or a
- *   field array structure. If the latter, $field['field_name'] must provided;
+ *   field array structure. If the latter, $field->id() must provided;
  *   it identifies the field that will be updated to match this structure. Any
  *   other properties of the field that are not specified in $field will be left
  *   unchanged, so it is not necessary to pass in a fully populated $field
@@ -93,7 +93,7 @@ function field_create_field(array $field) {
 function field_update_field($field) {
   // Module developers can still pass in an array of properties.
   if (is_array($field)) {
-    $field_loaded = entity_load('field_entity', $field['field_name']);
+    $field_loaded = entity_load('field_entity', $field->id());
     if (empty($field_loaded)) {
       throw new FieldException('Attempt to update a non-existent field.');
     }
@@ -250,7 +250,7 @@ function field_update_instance($instance) {
     }
     // Merge incoming values.
     foreach ($instance as $key => $value) {
-      $instance_loaded[$key] = $value;
+      $instance_loaded->$key = $value;
     }
     $instance = $instance_loaded;
   }
@@ -425,7 +425,7 @@ function field_purge_batch($batch_size) {
   $factory = Drupal::service('entity.query');
   $info = entity_get_info();
   foreach ($instances as $instance) {
-    $entity_type = $instance['entity_type'];
+    $entity_type = $instance->entity_type;
 
     // EntityFieldQuery currently fails on conditions on comment bundle.
     // Remove when http://drupal.org/node/731724 is fixed.
@@ -435,13 +435,13 @@ function field_purge_batch($batch_size) {
 
     $ids = (object) array(
       'entity_type' => $entity_type,
-      'bundle' => $instance['bundle'],
+      'bundle' => $instance->bundle,
     );
     // field_purge_data() will need the field array.
-    $field = field_info_field_by_id($instance['field_id']);
+    $field = field_info_field_by_id($instance->field_uuid);
     // Retrieve some entities.
     $query = $factory->get($entity_type)
-      ->condition('id:' . $field['uuid'] . '.deleted', 1)
+      ->condition('id:' . $field->uuid . '.deleted', 1)
       ->range(0, $batch_size);
     // If there's no bundle key, all results will have the same bundle.
     if (!empty($info[$entity_type]['entity_keys']['bundle'])) {
@@ -459,7 +459,7 @@ function field_purge_batch($batch_size) {
         $ids->entity_id = $entity_id;
         $entities[$entity_id] = _field_create_entity_from_ids($ids);
       }
-      field_attach_load($entity_type, $entities, FIELD_LOAD_CURRENT, array('field_id' => $field['uuid'], 'deleted' => 1));
+      field_attach_load($entity_type, $entities, FIELD_LOAD_CURRENT, array('field_id' => $field->uuid, 'deleted' => 1));
       foreach ($entities as $entity) {
         // Purge the data for the entity.
         field_purge_data($entity, $field, $instance);
@@ -475,7 +475,7 @@ function field_purge_batch($batch_size) {
   $deleted_fields = Drupal::state()->get('field.field.deleted') ?: array();
   foreach ($deleted_fields as $field) {
     $field = new Field($field);
-    $instances = field_read_instances(array('field_id' => $field['uuid']), array('include_deleted' => 1));
+    $instances = field_read_instances(array('field_id' => $field->uuid), array('include_deleted' => 1));
     if (empty($instances)) {
       field_purge_field($field);
     }
@@ -499,11 +499,11 @@ function field_purge_batch($batch_size) {
 function field_purge_data(EntityInterface $entity, $field, $instance) {
   // Each field type's hook_field_delete() only expects to operate on a single
   // field at a time, so we can use it as-is for purging.
-  $options = array('field_id' => $instance['field_id'], 'deleted' => TRUE);
+  $options = array('field_id' => $instance->field_uuid, 'deleted' => TRUE);
   _field_invoke('delete', $entity, $dummy, $dummy, $options);
 
   // Tell the field storage system to purge the data.
-  module_invoke($field['storage']['module'], 'field_storage_purge', $entity, $field, $instance);
+  module_invoke($field->storage['module'], 'field_storage_purge', $entity, $field, $instance);
 
   // Let other modules act on purging the data.
   foreach (module_implements('field_attach_purge') as $module) {
@@ -523,12 +523,12 @@ function field_purge_data(EntityInterface $entity, $field, $instance) {
  */
 function field_purge_instance($instance) {
   // Notify the storage engine.
-  $field = field_info_field_by_id($instance['field_id']);
-  module_invoke($field['storage']['module'], 'field_storage_purge_instance', $instance);
+  $field = field_info_field_by_id($instance->field_uuid);
+  module_invoke($field->storage['module'], 'field_storage_purge_instance', $instance);
 
   $state = Drupal::state();
   $deleted_instances = $state->get('field.instance.deleted');
-  unset($deleted_instances[$instance['uuid']]);
+  unset($deleted_instances[$instance->uuid]);
   $state->set('field.instance.deleted', $deleted_instances);
 
   // Clear the cache.
@@ -548,18 +548,18 @@ function field_purge_instance($instance) {
  *   The field record to purge.
  */
 function field_purge_field($field) {
-  $instances = field_read_instances(array('field_id' => $field['uuid']), array('include_deleted' => 1));
+  $instances = field_read_instances(array('field_id' => $field->uuid), array('include_deleted' => 1));
   if (count($instances) > 0) {
-    throw new FieldException(t('Attempt to purge a field @field_name that still has instances.', array('@field_name' => $field['field_name'])));
+    throw new FieldException(t('Attempt to purge a field @field_name that still has instances.', array('@field_name' => $field->id())));
   }
 
   $state = Drupal::state();
   $deleted_fields = $state->get('field.field.deleted');
-  unset($deleted_fields[$field['uuid']]);
+  unset($deleted_fields[$field->uuid]);
   $state->set('field.field.deleted', $deleted_fields);
 
   // Notify the storage engine.
-  module_invoke($field['storage']['module'], 'field_storage_purge_field', $field);
+  module_invoke($field->storage['module'], 'field_storage_purge_field', $field);
 
   // Clear the cache.
   field_info_cache_clear();
diff --git a/core/modules/field/field.default.inc b/core/modules/field/field.default.inc
index cc6a393..0bcd490 100644
--- a/core/modules/field/field.default.inc
+++ b/core/modules/field/field.default.inc
@@ -31,7 +31,7 @@
  * @param $langcode
  *   The language associated with $items.
  * @param $items
- *   $entity->{$field['field_name']}[$langcode], or an empty array if unset.
+ *   $entity->{$field->id()}[$langcode], or an empty array if unset.
  * @param $errors
  *   The array of errors, keyed by field name and by value delta, that have
  *   already been reported for the entity. The function should add its errors to
@@ -42,15 +42,15 @@
  */
 function field_default_validate(EntityInterface $entity, $field, $instance, $langcode, $items, &$errors) {
   // Filter out empty values.
-  $items = _field_filter_items($field['type'], $items);
+  $items = _field_filter_items($field->type, $items);
 
   // Check that the number of values doesn't exceed the field cardinality.
   // For form submitted values, this can only happen with 'multiple value'
   // widgets.
-  if ($field['cardinality'] != FIELD_CARDINALITY_UNLIMITED && count($items) > $field['cardinality']) {
-    $errors[$field['field_name']][$langcode][0][] = array(
+  if ($field->cardinality != FIELD_CARDINALITY_UNLIMITED && count($items) > $field->cardinality) {
+    $errors[$field->id()][$langcode][0][] = array(
       'error' => 'field_cardinality',
-      'message' => t('%name: this field cannot hold more than @count values.', array('%name' => $instance['label'], '@count' => $field['cardinality'])),
+      'message' => t('%name: this field cannot hold more than @count values.', array('%name' => $instance->label(), '@count' => $field->cardinality)),
     );
   }
 }
@@ -67,14 +67,14 @@ function field_default_validate(EntityInterface $entity, $field, $instance, $lan
  * @param $langcode
  *   The language the entity has to be translated to.
  * @param $items
- *   $entity->{$field['field_name']}[$langcode], or an empty array if unset.
+ *   $entity->{$field->id()}[$langcode], or an empty array if unset.
  * @param \Drupal\Core\Entity\EntityInterface $source_entity
  *   The source entity holding the field values to be translated.
  * @param $source_langcode
  *   The source language from which to translate.
  */
 function field_default_prepare_translation(EntityInterface $entity, $field, $instance, $langcode, &$items, EntityInterface $source_entity, $source_langcode) {
-  $field_name = $field['field_name'];
+  $field_name = $field->id();
   // If the field is untranslatable keep using Language::LANGCODE_NOT_SPECIFIED.
   if ($langcode == Language::LANGCODE_NOT_SPECIFIED) {
     $source_langcode = Language::LANGCODE_NOT_SPECIFIED;
diff --git a/core/modules/field/field.info.inc b/core/modules/field/field.info.inc
index f69649d..8cecbb2 100644
--- a/core/modules/field/field.info.inc
+++ b/core/modules/field/field.info.inc
@@ -145,7 +145,7 @@ function _field_info_collate_types_reset() {
  */
 function field_behaviors_widget($op, $instance) {
   $info = array();
-  if ($component = entity_get_form_display($instance['entity_type'], $instance['bundle'], 'default')->getComponent($instance['field_name'])) {
+  if ($component = entity_get_form_display($instance->entity_type, $instance->bundle, 'default')->getComponent($instance->getFieldName())) {
     $info = field_info_widget_types($component['type']);
   }
   return isset($info[$op]) ? $info[$op] : FIELD_BEHAVIOR_DEFAULT;
@@ -289,8 +289,8 @@ function field_info_fields() {
 
   $fields = array();
   foreach ($info as $key => $field) {
-    if (!$field['deleted']) {
-      $fields[$field['field_name']] = $field;
+    if (!$field->deleted) {
+      $fields[$field->id()] = $field;
     }
   }
 
diff --git a/core/modules/field/field.module b/core/modules/field/field.module
index 299ada6..c2809ec 100644
--- a/core/modules/field/field.module
+++ b/core/modules/field/field.module
@@ -208,7 +208,7 @@ function field_system_info_alter(&$info, $file, $type) {
       // remains no actual, non-deleted fields)
       $non_deleted = FALSE;
       foreach ($fields as $field) {
-        if (empty($field['deleted'])) {
+        if (empty($field->deleted)) {
           $non_deleted = TRUE;
           break;
         }
@@ -304,9 +304,9 @@ function field_entity_field_info($entity_type) {
       // @todo: Allow for adding field type settings.
       $definition = array(
         'label' => t('Field !name', array('!name' => $field_name)),
-        'type' => isset($field_types[$field['type']]['data_type']) ? $field_types[$field['type']]['data_type'] :  $field['type'] . '_field',
+        'type' => isset($field_types[$field->type]['data_type']) ? $field_types[$field->type]['data_type'] :  $field->type . '_field',
         'configurable' => TRUE,
-        'translatable' => !empty($field['translatable'])
+        'translatable' => !empty($field->translatable)
       );
 
       if ($optional) {
@@ -489,12 +489,12 @@ function field_sync_field_status() {
  */
 function field_get_default_value(EntityInterface $entity, $field, $instance, $langcode = NULL) {
   $items = array();
-  if (!empty($instance['default_value_function'])) {
-    $function = $instance['default_value_function'];
+  if (!empty($instance->default_value_function)) {
+    $function = $instance->default_value_function;
     $items = $function($entity, $field, $instance, $langcode);
   }
-  elseif (!empty($instance['default_value'])) {
-    $items = $instance['default_value'];
+  elseif (!empty($instance->default_value)) {
+    $items = $instance->default_value;
   }
   return $items;
 }
@@ -535,7 +535,7 @@ function _field_filter_items($field_type, $items) {
  *   The sorted array of field items.
  */
 function _field_sort_items($field, $items) {
-  if (($field['cardinality'] > 1 || $field['cardinality'] == FIELD_CARDINALITY_UNLIMITED) && isset($items[0]['_weight'])) {
+  if (($field->cardinality > 1 || $field->cardinality == FIELD_CARDINALITY_UNLIMITED) && isset($items[0]['_weight'])) {
     usort($items, '_field_sort_items_helper');
     foreach ($items as $delta => $item) {
       if (is_array($items[$delta])) {
@@ -808,7 +808,7 @@ function field_view_field(EntityInterface $entity, $field_name, $display_options
     // $display_options, so we cannot let preparation happen internally.
     $field = field_info_field($field_name);
     $formatter_manager = drupal_container()->get('plugin.manager.field.formatter');
-    $display_options = $formatter_manager->prepareConfiguration($field['type'], $display_options);
+    $display_options = $formatter_manager->prepareConfiguration($field->type, $display_options);
     $formatter = $formatter_manager->getInstance(array(
       'field_definition' => $instance,
       'view_mode' => $view_mode,
diff --git a/core/modules/field/field.multilingual.inc b/core/modules/field/field.multilingual.inc
index 6f6e2d6..5863cb1 100644
--- a/core/modules/field/field.multilingual.inc
+++ b/core/modules/field/field.multilingual.inc
@@ -30,7 +30,7 @@
  *
  * The available language codes for a particular field are returned by
  * field_available_languages(). Whether a field is translatable is determined by
- * calling field_is_translatable(), which checks the $field['translatable']
+ * calling field_is_translatable(), which checks the $field->translatable
  * property returned by field_info_field() and whether the entity type the field
  * is attached to supports translation.
  *
@@ -88,7 +88,7 @@ function field_available_languages($entity_type, $field) {
     $drupal_static_fast['field_langcodes'] = &drupal_static(__FUNCTION__);
   }
   $field_langcodes = &$drupal_static_fast['field_langcodes'];
-  $field_name = $field['field_name'];
+  $field_name = $field->id();
 
   if (!isset($field_langcodes[$entity_type][$field_name])) {
     // If the field has language support enabled we retrieve an (alterable) list
@@ -174,7 +174,7 @@ function field_language_fallback_enabled() {
  *   TRUE if the field can be translated.
  */
 function field_is_translatable($entity_type, $field) {
-  return $field['translatable'] && field_has_translation_handler($entity_type);
+  return $field->translatable && field_has_translation_handler($entity_type);
 }
 
 /**
@@ -267,17 +267,17 @@ function field_language(EntityInterface $entity, $field_name = NULL, $langcode =
     // if the field translation is not available. It is up to translation
     // handlers to implement language fallback rules.
     foreach (field_info_instances($entity_type, $bundle) as $instance) {
-      if (isset($entity->{$instance['field_name']}[$langcode])) {
-        $display_langcode[$instance['field_name']] = $langcode;
+      if (isset($entity->{$instance->getFieldName()}[$langcode])) {
+        $display_langcode[$instance->getFieldName()] = $langcode;
       }
       else {
         // If the field has a value for one of the locked languages, then use
         // that language for display. If not, the default one will be
         // Language::LANGCODE_NOT_SPECIFIED.
-        $display_langcode[$instance['field_name']] = Language::LANGCODE_NOT_SPECIFIED;
+        $display_langcode[$instance->getFieldName()] = Language::LANGCODE_NOT_SPECIFIED;
         foreach (language_list(Language::STATE_LOCKED) as $language_locked) {
-          if (isset($entity->{$instance['field_name']}[$language_locked->langcode])) {
-            $display_langcode[$instance['field_name']] = $language_locked->langcode;
+          if (isset($entity->{$instance->getFieldName()}[$language_locked->langcode])) {
+            $display_langcode[$instance->getFieldName()] = $language_locked->langcode;
             break;
           }
         }
diff --git a/core/modules/field/field.views.inc b/core/modules/field/field.views.inc
index 5a1f4f3..6b2efe9 100644
--- a/core/modules/field/field.views.inc
+++ b/core/modules/field/field.views.inc
@@ -18,11 +18,11 @@
 function field_views_data() {
   $data = array();
   foreach (field_info_fields() as $field) {
-    if ($field['storage']['type'] != 'field_sql_storage') {
+    if ($field->storage['type'] != 'field_sql_storage') {
       continue;
     }
 
-    $module = $field['module'];
+    $module = $field->module;
     $result = (array) module_invoke($module, 'field_views_data', $field);
 
     if (empty($result)) {
@@ -48,11 +48,11 @@ function field_views_data() {
  */
 function field_views_data_alter(&$data) {
   foreach (field_info_fields() as $field) {
-    if ($field['storage']['type'] != 'field_sql_storage') {
+    if ($field->storage['type'] != 'field_sql_storage') {
       continue;
     }
 
-    $function = $field['module'] . '_field_views_data_views_data_alter';
+    $function = $field->module . '_field_views_data_views_data_alter';
     if (function_exists($function)) {
       $function($data, $field);
     }
@@ -72,8 +72,8 @@ function field_views_field_label($field_name) {
   foreach ($instances as $entity_name => $entity_type) {
     foreach ($entity_type as $bundle) {
       if (isset($bundle[$field_name])) {
-        $label_counter[$bundle[$field_name]['label']] = isset($label_counter[$bundle[$field_name]['label']]) ? ++$label_counter[$bundle[$field_name]->label] : 1;
-        $all_labels[$entity_name][$bundle[$field_name]['label']] = TRUE;
+        $label_counter[$bundle[$field_name]->label] = isset($label_counter[$bundle[$field_name]->label]) ? ++$label_counter[$bundle[$field_name]->label] : 1;
+        $all_labels[$entity_name][$bundle[$field_name]->label] = TRUE;
       }
     }
   }
@@ -93,7 +93,7 @@ function field_views_field_default_views_data($field) {
   $field_types = field_info_field_types();
 
   // Check the field module is available.
-  if (!isset($field_types[$field['type']])) {
+  if (!isset($field_types[$field->type])) {
     return;
   }
 
@@ -110,10 +110,10 @@ function field_views_field_default_views_data($field) {
   $revision_tables = array();
   $groups = array();
 
-  $group_name = count($field['bundles']) > 1 ? t('Field') : NULL;
+  $group_name = count($field->getBundles()) > 1 ? t('Field') : NULL;
 
   // Build the relationships between the field table and the entity tables.
-  foreach ($field['bundles'] as $entity => $bundles) {
+  foreach ($field->getBundles() as $entity => $bundles) {
     $entity_info = entity_get_info($entity);
     $groups[$entity] = $entity_info['label'];
 
@@ -171,25 +171,25 @@ function field_views_field_default_views_data($field) {
   }
 
   $add_fields = array('delta', 'langcode', 'bundle');
-  foreach ($field['columns'] as $column_name => $attributes) {
-    $add_fields[] = _field_sql_storage_columnname($field['field_name'], $column_name);
+  foreach ($field->getSchema('columns') as $column_name => $attributes) {
+    $add_fields[] = _field_sql_storage_columnname($field->id(), $column_name);
   }
 
   // Note: we don't have a label available here, because we are at the field
   // level, not at the instance level. So we just go through all instances
   // and take the one which is used the most frequently.
-  $field_name = $field['field_name'];
+  $field_name = $field->id();
   list($label, $all_labels) = field_views_field_label($field_name);
   foreach ($tables as $type => $table) {
     if ($type == FIELD_LOAD_CURRENT) {
       $group = $group_name;
       $old_column = 'entity_id';
-      $column = $field['field_name'];
+      $column = $field->id();
     }
     else {
       $group = t('@group (historical data)', array('@group' => $group_name));
       $old_column = 'revision_id';
-      $column = $field['field_name'] . '-' . $old_column;
+      $column = $field->id() . '-' . $old_column;
     }
 
     $data[$table][$column] = array(
@@ -237,12 +237,12 @@ function field_views_field_default_views_data($field) {
       $data[$table][$column]['help'] .= ' ' . t('Also known as: !also.', array('!also' => implode(', ', $also_known)));
     }
 
-    $keys = array_keys($field['columns']);
+    $keys = array_keys($field->getSchema('columns'));
     $real_field = reset($keys);
     $data[$table][$column]['field'] = array(
       'table' => $table,
       'id' => 'field',
-      'field_name' => $field['field_name'],
+      'field_name' => $field->id(),
       // Provide a real field for group by.
       'real field' => $column . '_' . $real_field,
       'additional fields' => $add_fields,
@@ -253,7 +253,7 @@ function field_views_field_default_views_data($field) {
     );
   }
 
-  foreach ($field['columns'] as $column => $attributes) {
+  foreach ($field->getSchema('columns') as $column => $attributes) {
     $allow_sort = TRUE;
 
     // Identify likely filters and arguments for each column based on field type.
@@ -280,12 +280,12 @@ function field_views_field_default_views_data($field) {
         break;
     }
 
-    if (count($field['columns']) == 1 || $column == 'value') {
-      $title = t('@label (!name)', array('@label' => $label, '!name' => $field['field_name']));
+    if (count($field->getSchema('columns')) == 1 || $column == 'value') {
+      $title = t('@label (!name)', array('@label' => $label, '!name' => $field->id()));
       $title_short = $label;
     }
     else {
-      $title = t('@label (!name:!column)', array('@label' => $label, '!name' => $field['field_name'], '!column' => $column));
+      $title = t('@label (!name:!column)', array('@label' => $label, '!name' => $field->id(), '!column' => $column));
       $title_short = t('@label:!column', array('@label' => $label, '!column' => $column));
     }
 
@@ -296,10 +296,11 @@ function field_views_field_default_views_data($field) {
       else {
         $group = t('@group (historical data)', array('@group' => $group_name));
       }
-      $column_real_name = $field['storage_details']['sql'][$type][$table][$column];
+      $storage_details = $field->getStorageDetails();
+      $column_real_name = $storage_details['sql'][$type][$table][$column];
 
       // Load all the fields from the table by default.
-      $additional_fields = array_values($field['storage_details']['sql'][$type][$table]);
+      $additional_fields = array_values($storage_details['sql'][$type][$table]);
 
       $data[$table][$column_real_name] = array(
         'group' => $group,
@@ -315,11 +316,11 @@ function field_views_field_default_views_data($field) {
       foreach ($all_labels as $entity_name => $labels) {
         foreach ($labels as $label_name => $true) {
           if ($group_name != $groups[$entity_name] || $label != $label_name) {
-            if (count($field['columns']) == 1 || $column == 'value') {
-              $alias_title = t('@label (!name)', array('@label' => $label_name, '!name' => $field['field_name']));
+            if (count($field->getSchema('columns')) == 1 || $column == 'value') {
+              $alias_title = t('@label (!name)', array('@label' => $label_name, '!name' => $field->id()));
             }
             else {
-              $alias_title = t('@label (!name:!column)', array('@label' => $label_name, '!name' => $field['field_name'], '!column' => $column));
+              $alias_title = t('@label (!name:!column)', array('@label' => $label_name, '!name' => $field->id(), '!column' => $column));
             }
             $aliases[] = array(
               'group' => $groups[$entity_name],
@@ -340,7 +341,7 @@ function field_views_field_default_views_data($field) {
         'table' => $table,
         'id' => $argument,
         'additional fields' => $additional_fields,
-        'field_name' => $field['field_name'],
+        'field_name' => $field->id(),
         'empty field name' => t('- No value -'),
       );
       $data[$table][$column_real_name]['filter'] = array(
@@ -348,7 +349,7 @@ function field_views_field_default_views_data($field) {
         'table' => $table,
         'id' => $filter,
         'additional fields' => $additional_fields,
-        'field_name' => $field['field_name'],
+        'field_name' => $field->id(),
         'allow empty' => TRUE,
       );
       if (!empty($allow_sort)) {
@@ -357,13 +358,13 @@ function field_views_field_default_views_data($field) {
           'table' => $table,
           'id' => $sort,
           'additional fields' => $additional_fields,
-          'field_name' => $field['field_name'],
+          'field_name' => $field->id(),
         );
       }
 
       // Expose additional delta column for multiple value fields.
-      if ($field['cardinality'] > 1 || $field['cardinality'] == FIELD_CARDINALITY_UNLIMITED) {
-        $title_delta = t('@label (!name:delta)', array('@label' => $label, '!name' => $field['field_name']));
+      if ($field->cardinality > 1 || $field->cardinality == FIELD_CARDINALITY_UNLIMITED) {
+        $title_delta = t('@label (!name:delta)', array('@label' => $label, '!name' => $field->id()));
         $title_short_delta = t('@label:delta', array('@label' => $label));
 
         $data[$table]['delta'] = array(
@@ -381,14 +382,14 @@ function field_views_field_default_views_data($field) {
           'id' => 'numeric',
           'additional fields' => $additional_fields,
           'empty field name' => t('- No value -'),
-          'field_name' => $field['field_name'],
+          'field_name' => $field->id(),
         );
         $data[$table]['delta']['filter'] = array(
           'field' => 'delta',
           'table' => $table,
           'id' => 'numeric',
           'additional fields' => $additional_fields,
-          'field_name' => $field['field_name'],
+          'field_name' => $field->id(),
           'allow empty' => TRUE,
         );
         $data[$table]['delta']['sort'] = array(
@@ -396,13 +397,13 @@ function field_views_field_default_views_data($field) {
           'table' => $table,
           'id' => 'standard',
           'additional fields' => $additional_fields,
-          'field_name' => $field['field_name'],
+          'field_name' => $field->id(),
         );
       }
 
       // Expose additional language column for translatable fields.
-      if (!empty($field['translatable'])) {
-        $title_language = t('@label (!name:language)', array('@label' => $label, '!name' => $field['field_name']));
+      if (!empty($field->translatable)) {
+        $title_language = t('@label (!name:language)', array('@label' => $label, '!name' => $field->id()));
         $title_short_language = t('@label:language', array('@label' => $label));
 
         $data[$table]['language'] = array(
@@ -420,14 +421,14 @@ function field_views_field_default_views_data($field) {
           'id' => 'language',
           'additional fields' => $additional_fields,
           'empty field name' => t('<No value>'),
-          'field_name' => $field['field_name'],
+          'field_name' => $field->id(),
         );
         $data[$table]['language']['filter'] = array(
           'field' => 'language',
           'table' => $table,
           'id' => 'language',
           'additional fields' => $additional_fields,
-          'field_name' => $field['field_name'],
+          'field_name' => $field->id(),
           'allow empty' => TRUE,
         );
         $data[$table]['language']['sort'] = array(
@@ -435,7 +436,7 @@ function field_views_field_default_views_data($field) {
           'table' => $table,
           'id' => 'standard',
           'additional fields' => $additional_fields,
-          'field_name' => $field['field_name'],
+          'field_name' => $field->id(),
         );
       }
     }
@@ -455,7 +456,7 @@ function list_field_views_data($field) {
         $data[$table_name][$field_name]['filter']['id'] = 'field_list';
       }
       if (isset($field_data['argument']) && $field_name != 'delta') {
-        if ($field['type'] == 'list_text') {
+        if ($field->type == 'list_text') {
           $data[$table_name][$field_name]['argument']['id'] = 'field_list_string';
         }
         else {
diff --git a/core/modules/field/lib/Drupal/field/FieldInfo.php b/core/modules/field/lib/Drupal/field/FieldInfo.php
index 6d95788..f4fe7a9 100644
--- a/core/modules/field/lib/Drupal/field/FieldInfo.php
+++ b/core/modules/field/lib/Drupal/field/FieldInfo.php
@@ -223,7 +223,7 @@ public function getFields() {
     else {
       // Collect and prepare fields.
       foreach (field_read_fields(array(), array('include_deleted' => TRUE)) as $field) {
-        $this->fieldsById[$field['uuid']] = $this->prepareField($field);
+        $this->fieldsById[$field->uuid] = $this->prepareField($field);
       }
 
       // Store in persistent cache.
@@ -232,8 +232,8 @@ public function getFields() {
 
     // Fill the name/ID map.
     foreach ($this->fieldsById as $field) {
-      if (!$field['deleted']) {
-        $this->fieldIdsByName[$field['id']] = $field['uuid'];
+      if (!$field->deleted) {
+        $this->fieldIdsByName[$field->id()] = $field->uuid;
       }
     }
 
@@ -269,9 +269,9 @@ public function getInstances($entity_type = NULL) {
         $this->getFields();
 
         foreach (field_read_instances() as $instance) {
-          $field = $this->getField($instance['field_name']);
-          $instance = $this->prepareInstance($instance, $field['type']);
-          $this->bundleInstances[$instance['entity_type']][$instance['bundle']][$instance['field_name']] = $instance;
+          $field = $this->getField($instance->getFieldName());
+          $instance = $this->prepareInstance($instance, $field->type);
+          $this->bundleInstances[$instance->entity_type][$instance->bundle][$instance->getFieldName()] = $instance;
         }
 
         // Store in persistent cache.
@@ -317,8 +317,8 @@ public function getField($field_name) {
       $field = $this->prepareField($field);
 
       // Save in the "static" cache.
-      $this->fieldsById[$field['uuid']] = $field;
-      $this->fieldIdsByName[$field['field_name']] = $field['uuid'];
+      $this->fieldsById[$field->uuid] = $field;
+      $this->fieldIdsByName[$field->id()] = $field->uuid;
 
       return $field;
     }
@@ -356,9 +356,9 @@ public function getFieldById($field_id) {
       $field = $this->prepareField($field);
 
       // Store in the static cache.
-      $this->fieldsById[$field['uuid']] = $field;
-      if (!$field['deleted']) {
-        $this->fieldIdsByName[$field['field_name']] = $field['uuid'];
+      $this->fieldsById[$field->uuid] = $field;
+      if (!$field->deleted) {
+        $this->fieldIdsByName[$field->id()] = $field->uuid;
       }
 
       return $field;
@@ -397,10 +397,10 @@ public function getBundleInstances($entity_type, $bundle) {
 
       // Extract the field definitions and save them in the "static" cache.
       foreach ($info['fields'] as $field) {
-        if (!isset($this->fieldsById[$field['uuid']])) {
-          $this->fieldsById[$field['uuid']] = $field;
-          if (!$field['deleted']) {
-            $this->fieldIdsByName[$field['field_name']] = $field['uuid'];
+        if (!isset($this->fieldsById[$field->uuid])) {
+          $this->fieldsById[$field->uuid] = $field;
+          if (!$field->deleted) {
+            $this->fieldIdsByName[$field->id()] = $field->uuid;
           }
         }
       }
@@ -440,17 +440,17 @@ public function getBundleInstances($entity_type, $bundle) {
         $loaded_instances = entity_load_multiple('field_instance', array_values($config_ids));
 
         foreach ($loaded_instances as $instance) {
-          $field = $loaded_fields[$instance['field_name']];
+          $field = $loaded_fields[$instance->getFieldName()];
 
-          $instance = $this->prepareInstance($instance, $field['type']);
-          $instances[$field['field_name']] = $instance;
+          $instance = $this->prepareInstance($instance, $field->type);
+          $instances[$field->id()] = $instance;
 
           // If the field is not in our global "static" list yet, add it.
-          if (!isset($this->fieldsById[$field['uuid']])) {
+          if (!isset($this->fieldsById[$field->uuid])) {
             $field = $this->prepareField($field);
 
-            $this->fieldsById[$field['uuid']] = $field;
-            $this->fieldIdsByName[$field['field_name']] = $field['uuid'];
+            $this->fieldsById[$field->uuid] = $field;
+            $this->fieldIdsByName[$field->id()] = $field->uuid;
           }
         }
       }
@@ -473,7 +473,7 @@ public function getBundleInstances($entity_type, $bundle) {
       'fields' => array()
     );
     foreach ($instances as $instance) {
-      $cache['fields'][] = $this->fieldsById[$instance['field_id']];
+      $cache['fields'][] = $this->fieldsById[$instance->field_uuid];
     }
     $this->cacheBackend->set("field_info:bundle:$entity_type:$bundle", $cache, CacheBackendInterface::CACHE_PERMANENT, array('field_info' => TRUE));
 
@@ -532,8 +532,8 @@ public function getBundleExtraFields($entity_type, $bundle) {
    */
   public function prepareField($field) {
     // Make sure all expected field settings are present.
-    $field['settings'] += field_info_field_settings($field['type']);
-    $field['storage']['settings'] += field_info_storage_settings($field['storage']['type']);
+    $field->settings += field_info_field_settings($field->type);
+    $field->storage['settings'] += field_info_storage_settings($field->storage['type']);
 
     return $field;
   }
@@ -551,11 +551,11 @@ public function prepareField($field) {
    */
   public function prepareInstance($instance, $field_type) {
     // Make sure all expected instance settings are present.
-    $instance['settings'] += field_info_instance_settings($field_type);
+    $instance->settings += field_info_instance_settings($field_type);
 
     // Set a default value for the instance.
-    if (field_behaviors_widget('default value', $instance) == FIELD_BEHAVIOR_DEFAULT && !isset($instance['default_value'])) {
-      $instance['default_value'] = NULL;
+    if (field_behaviors_widget('default value', $instance) == FIELD_BEHAVIOR_DEFAULT && !isset($instance->default_value)) {
+      $instance->default_value = NULL;
     }
 
     return $instance;
diff --git a/core/modules/field/lib/Drupal/field/FieldInstanceInterface.php b/core/modules/field/lib/Drupal/field/FieldInstanceInterface.php
index d2a0b85..16d0aa2 100644
--- a/core/modules/field/lib/Drupal/field/FieldInstanceInterface.php
+++ b/core/modules/field/lib/Drupal/field/FieldInstanceInterface.php
@@ -13,7 +13,7 @@
 /**
  * Provides an interface defining a field instance entity.
  */
-interface FieldInstanceInterface extends ConfigEntityInterface, FieldDefinitionInterface, \ArrayAccess, \Serializable {
+interface FieldInstanceInterface extends ConfigEntityInterface, FieldDefinitionInterface, \Serializable {
 
   /**
    * Returns the field entity for this instance.
@@ -24,6 +24,22 @@
   public function getField();
 
   /**
+   * Returns the field id for this instance.
+   *
+   * @return $field_id
+   *   The field id.
+   */
+  public function getFieldName();
+
+  /**
+   * Returns the field type from the field for this instance.
+   *
+   * @return $type
+   *   The field type.
+   */
+  public function getFieldType();
+
+  /**
    * Allows a bundle to be renamed.
    *
    * Renaming a bundle on the instance is allowed when an entity's bundle
diff --git a/core/modules/field/lib/Drupal/field/FieldInterface.php b/core/modules/field/lib/Drupal/field/FieldInterface.php
index 83b3de7..24b51c3 100644
--- a/core/modules/field/lib/Drupal/field/FieldInterface.php
+++ b/core/modules/field/lib/Drupal/field/FieldInterface.php
@@ -13,11 +13,14 @@
 /**
  * Provides an interface defining a field entity.
  */
-interface FieldInterface extends ConfigEntityInterface, FieldDefinitionInterface, \ArrayAccess, \Serializable {
+interface FieldInterface extends ConfigEntityInterface, FieldDefinitionInterface, \Serializable {
 
   /**
    * Returns the field schema.
    *
+   * @param string $key
+   *   (optional) A key corresponding to one of the keys in the schema array.
+   *
    * @return array
    *   The field schema, as an array of key/value pairs in the format returned
    *   by hook_field_schema():
@@ -31,7 +34,7 @@
    *     however, that depending on the storage backend specified for the field,
    *     the field data is not necessarily stored in SQL.
    */
-  public function getSchema();
+  public function getSchema($key = '');
 
   /**
    * Returns information about how the storage backend stores the field data.
@@ -64,10 +67,13 @@ public function getStorageDetails();
   /**
    * Returns the list of bundles where the field has instances.
    *
+   * @param string $entity_type
+   *   (optional) The name of the entity type to look for.
+   *
    * @return array
    *   An array keyed by entity type names, whose values are arrays of bundle
    *   names.
    */
-  public function getBundles();
+  public function getBundles($entity_type = '');
 
 }
diff --git a/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/Field.php b/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/Field.php
index a8eb4b2..1d0eb20 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/Field.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/Field.php
@@ -492,7 +492,7 @@ public function delete() {
   /**
    * {@inheritdoc}
    */
-  public function getSchema() {
+  public function getSchema($key = '') {
     if (!isset($this->schema)) {
       $module_handler = \Drupal::moduleHandler();
 
@@ -516,6 +516,10 @@ public function getSchema() {
       $this->schema = $schema;
     }
 
+    if (!empty($key)) {
+      return $this->schema[$key];
+    }
+
     return $this->schema;
   }
 
@@ -541,10 +545,15 @@ public function getStorageDetails() {
   /**
    * {@inheritdoc}
    */
-  public function getBundles() {
+  public function getBundles($entity_type = '') {
     if (empty($this->deleted)) {
       $map = field_info_field_map();
-      if (isset($map[$this->id]['bundles'])) {
+      if (!empty($entity_type)) {
+        if (isset($map[$this->id]['bundles'][$entity_type])) {
+          return $map[$this->id]['bundles'][$entity_type];
+        }
+      }
+      elseif (isset($map[$this->id]['bundles'])) {
         return $map[$this->id]['bundles'];
       }
     }
@@ -645,62 +654,6 @@ public function isFieldRequired() {
   /**
    * {@inheritdoc}
    */
-  public function offsetExists($offset) {
-    return isset($this->{$offset}) || in_array($offset, array('columns', 'foreign keys', 'bundles', 'storage_details'));
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function &offsetGet($offset) {
-    switch ($offset) {
-      case 'id':
-        return $this->uuid;
-
-      case 'field_name':
-        return $this->id;
-
-      case 'columns':
-        $this->getSchema();
-        return $this->schema['columns'];
-
-      case 'foreign keys':
-        $this->getSchema();
-        return $this->schema['foreign keys'];
-
-      case 'bundles':
-        $bundles = $this->getBundles();
-        return $bundles;
-
-      case 'storage_details':
-        $this->getStorageDetails();
-        return $this->storageDetails;
-    }
-
-    return $this->{$offset};
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function offsetSet($offset, $value) {
-    if (!in_array($offset, array('columns', 'foreign keys', 'bundles', 'storage_details'))) {
-      $this->{$offset} = $value;
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function offsetUnset($offset) {
-    if (!in_array($offset, array('columns', 'foreign keys', 'bundles', 'storage_details'))) {
-      unset($this->{$offset});
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function serialize() {
     // Only store the definition, not external objects or derived data.
     return serialize($this->getExportProperties());
diff --git a/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/FieldInstance.php b/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/FieldInstance.php
index 2856acf..db4748b 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/FieldInstance.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/FieldInstance.php
@@ -571,6 +571,7 @@ public function isFieldRequired() {
     return $this->required;
   }
 
+
   /**
    * {@inheritdoc}
    */
@@ -581,46 +582,6 @@ public function allowBundleRename() {
   /**
    * {@inheritdoc}
    */
-  public function offsetExists($offset) {
-    return (isset($this->{$offset}) || $offset == 'field_id' || $offset == 'field_name');
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function &offsetGet($offset) {
-    if ($offset == 'field_id') {
-      return $this->field_uuid;
-    }
-    if ($offset == 'field_name') {
-      return $this->field->id;
-    }
-    return $this->{$offset};
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function offsetSet($offset, $value) {
-    if ($offset == 'field_id') {
-      $offset = 'field_uuid';
-    }
-    $this->{$offset} = $value;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function offsetUnset($offset) {
-    if ($offset == 'field_id') {
-      $offset = 'field_uuid';
-    }
-    unset($this->{$offset});
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function serialize() {
     // Only store the definition, not external objects or derived data.
     return serialize($this->getExportProperties());
diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetBase.php b/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetBase.php
index 5cf902b..777d6a1 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetBase.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetBase.php
@@ -46,7 +46,6 @@
    */
   public function __construct($plugin_id, array $plugin_definition, FieldDefinitionInterface $field_definition, array $settings) {
     parent::__construct(array(), $plugin_id, $plugin_definition);
-
     $this->fieldDefinition = $field_definition;
     $this->settings = $settings;
   }
diff --git a/core/modules/field/lib/Drupal/field/Plugin/views/field/Field.php b/core/modules/field/lib/Drupal/field/Plugin/views/field/Field.php
index 1342ec5..4333531 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/views/field/Field.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/views/field/Field.php
@@ -115,7 +115,7 @@ public function init(ViewExecutable $view, DisplayPluginBase $display, array &$o
     $this->multiple = FALSE;
     $this->limit_values = FALSE;
 
-    if ($field['cardinality'] > 1 || $field['cardinality'] == FIELD_CARDINALITY_UNLIMITED) {
+    if ($field->cardinality > 1 || $field->cardinality == FIELD_CARDINALITY_UNLIMITED) {
       $this->multiple = TRUE;
 
       // If "Display all values in the same row" is FALSE, then we always limit
@@ -131,7 +131,7 @@ public function init(ViewExecutable $view, DisplayPluginBase $display, array &$o
 
       // Otherwise, we only limit values if the user hasn't selected "all", 0, or
       // the value matching field cardinality.
-      if ((intval($this->options['delta_limit']) && ($this->options['delta_limit'] != $field['cardinality'])) || intval($this->options['delta_offset'])) {
+      if ((intval($this->options['delta_limit']) && ($this->options['delta_limit'] != $field->cardinality)) || intval($this->options['delta_offset'])) {
         $this->limit_values = TRUE;
       }
     }
@@ -299,8 +299,8 @@ protected function defineOptions() {
 
     // defineOptions runs before init/construct, so no $this->field_info
     $field = field_info_field($this->definition['field_name']);
-    $field_type = field_info_field_types($field['type']);
-    $column_names = array_keys($field['columns']);
+    $field_type = field_info_field_types($field->type);
+    $column_names = array_keys($field->getSchema('columns'));
     $default_column = '';
     // Try to determine a sensible default.
     if (count($column_names) == 1) {
@@ -335,7 +335,7 @@ protected function defineOptions() {
     // If we know the exact number of allowed values, then that can be
     // the default. Otherwise, default to 'all'.
     $options['delta_limit'] = array(
-      'default' => ($field['cardinality'] > 1) ? $field['cardinality'] : 'all',
+      'default' => ($field->cardinality > 1) ? $field->cardinality : 'all',
     );
     $options['delta_offset'] = array(
       'default' => 0,
@@ -371,8 +371,8 @@ public function buildOptionsForm(&$form, &$form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $field = $this->field_info;
-    $formatters = $this->formatterPluginManager->getOptions($field['type']);
-    $column_names = array_keys($field['columns']);
+    $formatters = $this->formatterPluginManager->getOptions($field->type);
+    $column_names = array_keys($field->getSchema('columns'));
 
     // If this is a multiple value field, add its options.
     if ($this->multiple) {
@@ -380,7 +380,7 @@ public function buildOptionsForm(&$form, &$form_state) {
     }
 
     // No need to ask the user anything if the field has only one column.
-    if (count($field['columns']) == 1) {
+    if (count($field->getSchema('columns')) == 1) {
       $form['click_sort_column'] = array(
         '#type' => 'value',
         '#value' => isset($column_names[0]) ? $column_names[0] : '',
@@ -471,14 +471,14 @@ function multiple_options_form(&$form, &$form_state) {
     // translating prefix and suffix separately.
     list($prefix, $suffix) = explode('@count', t('Display @count value(s)'));
 
-    if ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED) {
+    if ($field->cardinality == FIELD_CARDINALITY_UNLIMITED) {
       $type = 'textfield';
       $options = NULL;
       $size = 5;
     }
     else {
       $type = 'select';
-      $options = drupal_map_assoc(range(1, $field['cardinality']));
+      $options = drupal_map_assoc(range(1, $field->cardinality));
       $size = 1;
     }
     $form['multi_type'] = array(
@@ -798,14 +798,14 @@ function render_item($count, $item) {
 
   protected function documentSelfTokens(&$tokens) {
     $field = $this->field_info;
-    foreach ($field['columns'] as $id => $column) {
+    foreach ($field->getSchema('columns') as $id => $column) {
       $tokens['[' . $this->options['id'] . '-' . $id . ']'] = t('Raw @column', array('@column' => $id));
     }
   }
 
   protected function addSelfTokens(&$tokens, $item) {
     $field = $this->field_info;
-    foreach ($field['columns'] as $id => $column) {
+    foreach ($field->getSchema('columns') as $id => $column) {
       // Use filter_xss_admin because it's user data and we can't be sure it is safe.
       // We know nothing about the data, though, so we can't really do much else.
 
diff --git a/core/modules/field/lib/Drupal/field/Tests/BulkDeleteTest.php b/core/modules/field/lib/Drupal/field/Tests/BulkDeleteTest.php
index d27bd7d..986599f 100644
--- a/core/modules/field/lib/Drupal/field/Tests/BulkDeleteTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/BulkDeleteTest.php
@@ -116,7 +116,7 @@ function setUp() {
     foreach ($this->bundles as $bundle) {
       foreach ($this->fields as $field) {
         $instance = array(
-          'field_name' => $field['field_name'],
+          'field_name' => $field->id(),
           'entity_type' => $this->entity_type,
           'bundle' => $bundle,
         );
@@ -126,7 +126,7 @@ function setUp() {
       for ($i = 0; $i < 10; $i++) {
         $entity = field_test_create_entity($id, $id, $bundle);
         foreach ($this->fields as $field) {
-          $entity->{$field['field_name']}[Language::LANGCODE_NOT_SPECIFIED] = $this->_generateTestFieldValues($field['cardinality']);
+          $entity->{$field->id()}[Language::LANGCODE_NOT_SPECIFIED] = $this->_generateTestFieldValues($field->cardinality);
         }
         $entity->save();
         $id++;
@@ -151,7 +151,7 @@ function setUp() {
   function testDeleteFieldInstance() {
     $bundle = reset($this->bundles);
     $field = reset($this->fields);
-    $field_name = $field['field_name'];
+    $field_name = $field->id();
     $factory = \Drupal::service('entity.query');
 
     // There are 10 entities of this bundle.
@@ -161,13 +161,13 @@ function testDeleteFieldInstance() {
     $this->assertEqual(count($found), 10, 'Correct number of entities found before deleting');
 
     // Delete the instance.
-    $instance = field_info_instance($this->entity_type, $field['field_name'], $bundle);
+    $instance = field_info_instance($this->entity_type, $field->id(), $bundle);
     field_delete_instance($instance);
 
     // The instance still exists, deleted.
-    $instances = field_read_instances(array('field_id' => $field['uuid'], 'deleted' => TRUE), array('include_deleted' => TRUE, 'include_inactive' => TRUE));
+    $instances = field_read_instances(array('field_id' => $field->uuid, 'deleted' => TRUE), array('include_deleted' => TRUE, 'include_inactive' => TRUE));
     $this->assertEqual(count($instances), 1, 'There is one deleted instance');
-    $this->assertEqual($instances[0]['bundle'], $bundle, 'The deleted instance is for the correct bundle');
+    $this->assertEqual($instances[0]->bundle, $bundle, 'The deleted instance is for the correct bundle');
 
     // There are 0 entities of this bundle with non-deleted data.
     $found = $factory->get('test_entity')
@@ -192,10 +192,10 @@ function testDeleteFieldInstance() {
       $ids->entity_id = $entity_id;
       $entities[$entity_id] = _field_create_entity_from_ids($ids);
     }
-    field_attach_load($this->entity_type, $entities, FIELD_LOAD_CURRENT, array('field_id' => $field['uuid'], 'deleted' => TRUE));
+    field_attach_load($this->entity_type, $entities, FIELD_LOAD_CURRENT, array('field_id' => $field->uuid, 'deleted' => TRUE));
     $this->assertEqual(count($found), 10, 'Correct number of entities found after deleting');
     foreach ($entities as $id => $entity) {
-      $this->assertEqual($this->entities[$id]->{$field['field_name']}, $entity->{$field['field_name']}, "Entity $id with deleted data loaded correctly");
+      $this->assertEqual($this->entities[$id]->{$field->id()}, $entity->{$field->id()}, "Entity $id with deleted data loaded correctly");
     }
   }
 
@@ -211,7 +211,7 @@ function testPurgeInstance() {
     $field = reset($this->fields);
 
     // Delete the instance.
-    $instance = field_info_instance($this->entity_type, $field['field_name'], $bundle);
+    $instance = field_info_instance($this->entity_type, $field->id(), $bundle);
     field_delete_instance($instance);
 
     // No field hooks were called.
@@ -226,7 +226,7 @@ function testPurgeInstance() {
       // There are $count deleted entities left.
       $found = \Drupal::entityQuery('test_entity')
         ->condition('fttype', $bundle)
-        ->condition($field['field_name'] . '.deleted', 1)
+        ->condition($field->id() . '.deleted', 1)
         ->execute();
       $this->assertEqual(count($found), $count, 'Correct number of entities found after purging 2');
     }
@@ -238,7 +238,7 @@ function testPurgeInstance() {
     // bundle.
     $actual_hooks = field_test_memorize();
     $hooks = array();
-    $entities = $this->convertToPartialEntities($this->entities_by_bundles[$bundle], $field['field_name']);
+    $entities = $this->convertToPartialEntities($this->entities_by_bundles[$bundle], $field->id());
     foreach (array_chunk($entities, $batch_size, TRUE) as $chunk_entity) {
       $hooks['field_test_field_load'][] = $chunk_entity;
     }
@@ -248,19 +248,19 @@ function testPurgeInstance() {
     $this->checkHooksInvocations($hooks, $actual_hooks);
 
     // The instance still exists, deleted.
-    $instances = field_read_instances(array('field_id' => $field['uuid'], 'deleted' => TRUE), array('include_deleted' => TRUE, 'include_inactive' => TRUE));
+    $instances = field_read_instances(array('field_id' => $field->uuid, 'deleted' => TRUE), array('include_deleted' => TRUE, 'include_inactive' => TRUE));
     $this->assertEqual(count($instances), 1, 'There is one deleted instance');
 
     // Purge the instance.
     field_purge_batch($batch_size);
 
     // The instance is gone.
-    $instances = field_read_instances(array('field_id' => $field['uuid'], 'deleted' => TRUE), array('include_deleted' => TRUE, 'include_inactive' => TRUE));
+    $instances = field_read_instances(array('field_id' => $field->uuid, 'deleted' => TRUE), array('include_deleted' => TRUE, 'include_inactive' => TRUE));
     $this->assertEqual(count($instances), 0, 'The instance is gone');
 
     // The field still exists, not deleted, because it has a second instance.
-    $fields = field_read_fields(array('uuid' => $field['uuid']), array('include_deleted' => TRUE, 'include_inactive' => TRUE));
-    $this->assertTrue(isset($fields[$field['uuid']]), 'The field exists and is not deleted');
+    $fields = field_read_fields(array('uuid' => $field->uuid), array('include_deleted' => TRUE, 'include_inactive' => TRUE));
+    $this->assertTrue(isset($fields[$field->uuid]), 'The field exists and is not deleted');
   }
 
   /**
@@ -275,7 +275,7 @@ function testPurgeField() {
 
     // Delete the first instance.
     $bundle = reset($this->bundles);
-    $instance = field_info_instance($this->entity_type, $field['field_name'], $bundle);
+    $instance = field_info_instance($this->entity_type, $field->id(), $bundle);
     field_delete_instance($instance);
 
     // Assert that hook_field_delete() was not called yet.
@@ -292,7 +292,7 @@ function testPurgeField() {
     // bundle.
     $actual_hooks = field_test_memorize();
     $hooks = array();
-    $entities = $this->convertToPartialEntities($this->entities_by_bundles[$bundle], $field['field_name']);
+    $entities = $this->convertToPartialEntities($this->entities_by_bundles[$bundle], $field->id());
     $hooks['field_test_field_load'][] = $entities;
     $hooks['field_test_field_delete'] = $entities;
     $this->checkHooksInvocations($hooks, $actual_hooks);
@@ -301,12 +301,12 @@ function testPurgeField() {
     field_purge_batch(0);
 
     // The field still exists, not deleted.
-    $fields = field_read_fields(array('uuid' => $field['uuid']), array('include_deleted' => TRUE));
-    $this->assertTrue(isset($fields[$field['uuid']]) && !$fields[$field['uuid']]->deleted, 'The field exists and is not deleted');
+    $fields = field_read_fields(array('uuid' => $field->uuid), array('include_deleted' => TRUE));
+    $this->assertTrue(isset($fields[$field->uuid]) && !$fields[$field->uuid]->deleted, 'The field exists and is not deleted');
 
     // Delete the second instance.
     $bundle = next($this->bundles);
-    $instance = field_info_instance($this->entity_type, $field['field_name'], $bundle);
+    $instance = field_info_instance($this->entity_type, $field->id(), $bundle);
     field_delete_instance($instance);
 
     // Assert that hook_field_delete() was not called yet.
@@ -319,20 +319,20 @@ function testPurgeField() {
     // Check hooks invocations (same as above, for the 2nd bundle).
     $actual_hooks = field_test_memorize();
     $hooks = array();
-    $entities = $this->convertToPartialEntities($this->entities_by_bundles[$bundle], $field['field_name']);
+    $entities = $this->convertToPartialEntities($this->entities_by_bundles[$bundle], $field->id());
     $hooks['field_test_field_load'][] = $entities;
     $hooks['field_test_field_delete'] = $entities;
     $this->checkHooksInvocations($hooks, $actual_hooks);
 
     // The field still exists, deleted.
-    $fields = field_read_fields(array('uuid' => $field['uuid']), array('include_deleted' => TRUE));
-    $this->assertTrue(isset($fields[$field['uuid']]) && $fields[$field['uuid']]->deleted, 'The field exists and is deleted');
+    $fields = field_read_fields(array('uuid' => $field->uuid), array('include_deleted' => TRUE));
+    $this->assertTrue(isset($fields[$field->uuid]) && $fields[$field->uuid]->deleted, 'The field exists and is deleted');
 
     // Purge again to purge the instance and the field.
     field_purge_batch(0);
 
     // The field is gone.
-    $fields = field_read_fields(array('uuid' => $field['uuid']), array('include_deleted' => TRUE, 'include_inactive' => TRUE));
+    $fields = field_read_fields(array('uuid' => $field->uuid), array('include_deleted' => TRUE, 'include_inactive' => TRUE));
     $this->assertEqual(count($fields), 0, 'The field is purged.');
   }
 }
diff --git a/core/modules/field/lib/Drupal/field/Tests/CrudTest.php b/core/modules/field/lib/Drupal/field/Tests/CrudTest.php
index 7960f82..34cabbc 100644
--- a/core/modules/field/lib/Drupal/field/Tests/CrudTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/CrudTest.php
@@ -43,8 +43,8 @@ function testCreateField() {
     field_test_memorize();
     $field = field_create_field($field_definition);
     $mem = field_test_memorize();
-    $this->assertIdentical($mem['field_test_field_create_field'][0][0]['field_name'], $field_definition['field_name'], 'hook_field_create_field() called with correct arguments.');
-    $this->assertIdentical($mem['field_test_field_create_field'][0][0]['type'], $field_definition['type'], 'hook_field_create_field() called with correct arguments.');
+    $this->assertIdentical($mem['field_test_field_create_field'][0][0]->field_name, $field_definition['field_name'], 'hook_field_create_field() called with correct arguments.');
+    $this->assertIdentical($mem['field_test_field_create_field'][0][0]->type, $field_definition['type'], 'hook_field_create_field() called with correct arguments.');
 
     // Read the configuration. Check against raw configuration data rather than
     // the loaded ConfigEntity, to be sure we check that the defaults are
@@ -275,38 +275,38 @@ function testDeleteField() {
 
     // Create two fields (so we can test that only one is deleted).
     $this->field = array('field_name' => 'field_1', 'type' => 'test_field');
-    field_create_field($this->field);
+    $this->field = field_create_field($this->field);
     $this->another_field = array('field_name' => 'field_2', 'type' => 'test_field');
     field_create_field($this->another_field);
 
     // Create instances for each.
     $this->instance_definition = array(
-      'field_name' => $this->field['field_name'],
+      'field_name' => $this->field->id(),
       'entity_type' => 'test_entity',
       'bundle' => 'test_bundle',
     );
     field_create_instance($this->instance_definition);
     $this->another_instance_definition = $this->instance_definition;
-    $this->another_instance_definition['field_name'] = $this->another_field['field_name'];
+    $this->another_instance_definition['field_name'] = $this->another_field->id();
     field_create_instance($this->another_instance_definition);
 
     // Test that the first field is not deleted, and then delete it.
-    $field = field_read_field($this->field['field_name'], array('include_deleted' => TRUE));
-    $this->assertTrue(!empty($field) && empty($field['deleted']), 'A new field is not marked for deletion.');
-    field_delete_field($this->field['field_name']);
+    $field = field_read_field($this->field->id(), array('include_deleted' => TRUE));
+    $this->assertTrue(!empty($field) && empty($field->deleted), 'A new field is not marked for deletion.');
+    field_delete_field($this->field->id());
 
     // Make sure that the field is marked as deleted when it is specifically
     // loaded.
-    $field = field_read_field($this->field['field_name'], array('include_deleted' => TRUE));
-    $this->assertTrue(!empty($field['deleted']), 'A deleted field is marked for deletion.');
+    $field = field_read_field($this->field->id(), array('include_deleted' => TRUE));
+    $this->assertTrue(!empty($field->deleted), 'A deleted field is marked for deletion.');
 
     // Make sure that this field's instance is marked as deleted when it is
     // specifically loaded.
     $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle'], array('include_deleted' => TRUE));
-    $this->assertTrue(!empty($instance['deleted']), 'An instance for a deleted field is marked for deletion.');
+    $this->assertTrue(!empty($instance->deleted), 'An instance for a deleted field is marked for deletion.');
 
     // Try to load the field normally and make sure it does not show up.
-    $field = field_read_field($this->field['field_name']);
+    $field = field_read_field($this->field->id());
     $this->assertTrue(empty($field), 'A deleted field is not loaded by default.');
 
     // Try to load the instance normally and make sure it does not show up.
@@ -314,34 +314,34 @@ function testDeleteField() {
     $this->assertTrue(empty($instance), 'An instance for a deleted field is not loaded by default.');
 
     // Make sure the other field (and its field instance) are not deleted.
-    $another_field = field_read_field($this->another_field['field_name']);
-    $this->assertTrue(!empty($another_field) && empty($another_field['deleted']), 'A non-deleted field is not marked for deletion.');
+    $another_field = field_read_field($this->another_field->id());
+    $this->assertTrue(!empty($another_field) && empty($another_field->deleted), 'A non-deleted field is not marked for deletion.');
     $another_instance = field_read_instance('test_entity', $this->another_instance_definition['field_name'], $this->another_instance_definition['bundle']);
-    $this->assertTrue(!empty($another_instance) && empty($another_instance['deleted']), 'An instance of a non-deleted field is not marked for deletion.');
+    $this->assertTrue(!empty($another_instance) && empty($another_instance->deleted), 'An instance of a non-deleted field is not marked for deletion.');
 
     // Try to create a new field the same name as a deleted field and
     // write data into it.
     field_create_field($this->field);
     field_create_instance($this->instance_definition);
-    $field = field_read_field($this->field['field_name']);
-    $this->assertTrue(!empty($field) && empty($field['deleted']), 'A new field with a previously used name is created.');
+    $field = field_read_field($this->field->id());
+    $this->assertTrue(!empty($field) && empty($field->deleted), 'A new field with a previously used name is created.');
     $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
-    $this->assertTrue(!empty($instance) && empty($instance['deleted']), 'A new instance for a previously used field name is created.');
+    $this->assertTrue(!empty($instance) && empty($instance->deleted), 'A new instance for a previously used field name is created.');
 
     // Save an entity with data for the field
-    $entity = field_test_create_entity(0, 0, $instance['bundle']);
+    $entity = field_test_create_entity(0, 0, $instance->bundle);
     $langcode = Language::LANGCODE_NOT_SPECIFIED;
     $values[0]['value'] = mt_rand(1, 127);
-    $entity->{$field['field_name']}[$langcode] = $values;
+    $entity->{$field->id()}[$langcode] = $values;
     $entity_type = 'test_entity';
     field_attach_insert($entity);
 
     // Verify the field is present on load
     $entity = field_test_create_entity(0, 0, $this->instance_definition['bundle']);
     field_attach_load($entity_type, array(0 => $entity));
-    $this->assertIdentical(count($entity->{$field['field_name']}[$langcode]), count($values), "Data in previously deleted field saves and loads correctly");
+    $this->assertIdentical(count($entity->{$field->id()}[$langcode]), count($values), "Data in previously deleted field saves and loads correctly");
     foreach ($values as $delta => $value) {
-      $this->assertEqual($entity->{$field['field_name']}[$langcode][$delta]['value'], $values[$delta]['value'], "Data in previously deleted field saves and loads correctly");
+      $this->assertEqual($entity->{$field->id()}[$langcode][$delta]['value'], $values[$delta]['value'], "Data in previously deleted field saves and loads correctly");
     }
   }
 
@@ -381,7 +381,7 @@ function testUpdateField() {
     do {
       // We need a unique ID for our entity. $cardinality will do.
       $id = $cardinality;
-      $entity = field_test_create_entity($id, $id, $instance['bundle']);
+      $entity = field_test_create_entity($id, $id, $instance->bundle);
       // Fill in the entity with more values than $cardinality.
       for ($i = 0; $i < 20; $i++) {
         $entity->field_update[Language::LANGCODE_NOT_SPECIFIED][$i]['value'] = $i;
@@ -389,15 +389,15 @@ function testUpdateField() {
       // Save the entity.
       field_attach_insert($entity);
       // Load back and assert there are $cardinality number of values.
-      $entity = field_test_create_entity($id, $id, $instance['bundle']);
+      $entity = field_test_create_entity($id, $id, $instance->bundle);
       field_attach_load('test_entity', array($id => $entity));
-      $this->assertEqual(count($entity->field_update[Language::LANGCODE_NOT_SPECIFIED]), $field['cardinality'], 'Cardinality is kept');
+      $this->assertEqual(count($entity->field_update[Language::LANGCODE_NOT_SPECIFIED]), $field->cardinality, 'Cardinality is kept');
       // Now check the values themselves.
       for ($delta = 0; $delta < $cardinality; $delta++) {
         $this->assertEqual($entity->field_update[Language::LANGCODE_NOT_SPECIFIED][$delta]['value'], $delta, 'Value is kept');
       }
       // Increase $cardinality and set the field cardinality to the new value.
-      $field['cardinality'] = ++$cardinality;
+      $field->cardinality = ++$cardinality;
       field_update_field($field);
     } while ($cardinality < 6);
   }
@@ -408,7 +408,7 @@ function testUpdateField() {
   function testUpdateFieldForbid() {
     $field = array('field_name' => 'forbidden', 'type' => 'test_field', 'settings' => array('changeable' => 0, 'unchangeable' => 0));
     $field = field_create_field($field);
-    $field['settings']['changeable']++;
+    $field->settings['changeable']++;
     try {
       field_update_field($field);
       $this->pass(t("A changeable setting can be updated."));
@@ -416,7 +416,7 @@ function testUpdateFieldForbid() {
     catch (FieldException $e) {
       $this->fail(t("An unchangeable setting cannot be updated."));
     }
-    $field['settings']['unchangeable']++;
+    $field->settings['unchangeable']++;
     try {
       field_update_field($field);
       $this->fail(t("An unchangeable setting can be updated."));
diff --git a/core/modules/field/lib/Drupal/field/Tests/DisplayApiTest.php b/core/modules/field/lib/Drupal/field/Tests/DisplayApiTest.php
index 9ca988e..f48a69a 100644
--- a/core/modules/field/lib/Drupal/field/Tests/DisplayApiTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/DisplayApiTest.php
@@ -57,11 +57,11 @@ function setUp() {
     field_create_field($this->field);
     field_create_instance($this->instance);
     // Create a display for the default view mode.
-    entity_get_display($this->instance['entity_type'], $this->instance['bundle'], 'default')
+    entity_get_display($this->instance->entity_type, $this->instance->bundle, 'default')
       ->setComponent($this->field_name, $this->display_options['default'])
       ->save();
     // Create a display for the teaser view mode.
-    entity_get_display($this->instance['entity_type'], $this->instance['bundle'], 'teaser')
+    entity_get_display($this->instance->entity_type, $this->instance->bundle, 'teaser')
       ->setComponent($this->field_name, $this->display_options['teaser'])
       ->save();
 
diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldAccessTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldAccessTest.php
index b63d48d..825f010 100644
--- a/core/modules/field/lib/Drupal/field/Tests/FieldAccessTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/FieldAccessTest.php
@@ -41,9 +41,9 @@ function setUp() {
       'field_name' => 'test_view_field',
       'type' => 'text',
     );
-    field_create_field($this->field);
+    $this->field = field_create_field($this->field);
     $this->instance = array(
-      'field_name' => $this->field['field_name'],
+      'field_name' => $this->field->id(),
       'entity_type' => 'node',
       'bundle' => $this->content_type,
     );
@@ -52,7 +52,7 @@ function setUp() {
     // Assign display properties for the 'default' and 'teaser' view modes.
     foreach (array('default', 'teaser') as $view_mode) {
       entity_get_display('node', $this->content_type, $view_mode)
-        ->setComponent($this->field['field_name'])
+        ->setComponent($this->field->id())
         ->save();
     }
 
diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldAttachOtherTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldAttachOtherTest.php
index d16b25a..8c5f3a5 100644
--- a/core/modules/field/lib/Drupal/field/Tests/FieldAttachOtherTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/FieldAttachOtherTest.php
@@ -39,9 +39,9 @@ function testFieldAttachView() {
     $options = array('field_name' => $this->field_name_2);
 
     // Populate values to be displayed.
-    $values = $this->_generateTestFieldValues($this->field['cardinality']);
+    $values = $this->_generateTestFieldValues($this->field->cardinality);
     $entity_init->{$this->field_name}[$langcode] = $values;
-    $values_2 = $this->_generateTestFieldValues($this->field_2['cardinality']);
+    $values_2 = $this->_generateTestFieldValues($this->field_2->cardinality);
     $entity_init->{$this->field_name_2}[$langcode] = $values_2;
 
     // Simple formatter, label displayed.
@@ -57,7 +57,7 @@ function testFieldAttachView() {
         'test_formatter_setting' => $formatter_setting,
       ),
     );
-    $display->setComponent($this->field['field_name'], $display_options);
+    $display->setComponent($this->field->id(), $display_options);
 
     $formatter_setting_2 = $this->randomName();
     $display_options_2 = array(
@@ -67,19 +67,19 @@ function testFieldAttachView() {
         'test_formatter_setting' => $formatter_setting_2,
       ),
     );
-    $display->setComponent($this->field_2['field_name'], $display_options_2);
+    $display->setComponent($this->field_2->id(), $display_options_2);
 
     // View all fields.
     field_attach_prepare_view($entity_type, array($entity->ftid => $entity), $displays);
     $entity->content = field_attach_view($entity, $display);
     $output = drupal_render($entity->content);
     $this->content = $output;
-    $this->assertRaw($this->instance['label'], "First field's label is displayed.");
+    $this->assertRaw($this->instance->label, "First field's label is displayed.");
     foreach ($values as $delta => $value) {
       $this->content = $output;
       $this->assertRaw("$formatter_setting|{$value['value']}", "Value $delta is displayed, formatter settings are applied.");
     }
-    $this->assertRaw($this->instance_2['label'], "Second field's label is displayed.");
+    $this->assertRaw($this->instance_2->label, "Second field's label is displayed.");
     foreach ($values_2 as $delta => $value) {
       $this->content = $output;
       $this->assertRaw("$formatter_setting_2|{$value['value']}", "Value $delta is displayed, formatter settings are applied.");
@@ -89,12 +89,12 @@ function testFieldAttachView() {
     $entity->content = field_attach_view($entity, $display, $langcode, $options);
     $output = drupal_render($entity->content);
     $this->content = $output;
-    $this->assertNoRaw($this->instance['label'], "First field's label is not displayed.");
+    $this->assertNoRaw($this->instance->label, "First field's label is not displayed.");
     foreach ($values as $delta => $value) {
       $this->content = $output;
       $this->assertNoRaw("$formatter_setting|{$value['value']}", "Value $delta is displayed, formatter settings are applied.");
     }
-    $this->assertRaw($this->instance_2['label'], "Second field's label is displayed.");
+    $this->assertRaw($this->instance_2->label, "Second field's label is displayed.");
     foreach ($values_2 as $delta => $value) {
       $this->content = $output;
       $this->assertRaw("$formatter_setting_2|{$value['value']}", "Value $delta is displayed, formatter settings are applied.");
@@ -103,21 +103,21 @@ function testFieldAttachView() {
     // Label hidden.
     $entity = clone($entity_init);
     $display_options['label'] = 'hidden';
-    $display->setComponent($this->field['field_name'], $display_options);
+    $display->setComponent($this->field->id(), $display_options);
     field_attach_prepare_view($entity_type, array($entity->ftid => $entity), $displays);
     $entity->content = field_attach_view($entity, $display);
     $output = drupal_render($entity->content);
     $this->content = $output;
-    $this->assertNoRaw($this->instance['label'], "Hidden label: label is not displayed.");
+    $this->assertNoRaw($this->instance->label, "Hidden label: label is not displayed.");
 
     // Field hidden.
     $entity = clone($entity_init);
-    $display->removeComponent($this->field['field_name']);
+    $display->removeComponent($this->field->id());
     field_attach_prepare_view($entity_type, array($entity->ftid => $entity), $displays);
     $entity->content = field_attach_view($entity, $display);
     $output = drupal_render($entity->content);
     $this->content = $output;
-    $this->assertNoRaw($this->instance['label'], "Hidden field: label is not displayed.");
+    $this->assertNoRaw($this->instance->label, "Hidden field: label is not displayed.");
     foreach ($values as $delta => $value) {
       $this->assertNoRaw("$formatter_setting|{$value['value']}", "Hidden field: value $delta is not displayed.");
     }
@@ -125,7 +125,7 @@ function testFieldAttachView() {
     // Multiple formatter.
     $entity = clone($entity_init);
     $formatter_setting = $this->randomName();
-    $display->setComponent($this->field['field_name'], array(
+    $display->setComponent($this->field->id(), array(
       'label' => 'above',
       'type' => 'field_test_multiple',
       'settings' => array(
@@ -145,7 +145,7 @@ function testFieldAttachView() {
     // Test a formatter that uses hook_field_formatter_prepare_view().
     $entity = clone($entity_init);
     $formatter_setting = $this->randomName();
-    $display->setComponent($this->field['field_name'], array(
+    $display->setComponent($this->field->id(), array(
       'label' => 'above',
       'type' => 'field_test_with_prepare_view',
       'settings' => array(
@@ -186,18 +186,18 @@ function testFieldAttachPrepareViewMultiple() {
 
     // Set the instance to be hidden.
     $display = entity_get_display('test_entity', 'test_bundle', 'full')
-      ->removeComponent($this->field['field_name']);
+      ->removeComponent($this->field->id());
 
     // Set up a second instance on another bundle, with a formatter that uses
     // hook_field_formatter_prepare_view().
     field_test_create_bundle('test_bundle_2');
     $formatter_setting = $this->randomName();
     $this->instance2 = $this->instance;
-    $this->instance2['bundle'] = 'test_bundle_2';
+    $this->instance2->bundle = 'test_bundle_2';
     field_create_instance($this->instance2);
 
     $display_2 = entity_get_display('test_entity', 'test_bundle_2', 'full')
-      ->setComponent($this->field['field_name'], array(
+      ->setComponent($this->field->id(), array(
         'type' => 'field_test_with_prepare_view',
         'settings' => array(
           'test_formatter_setting_additional' => $formatter_setting,
@@ -208,11 +208,11 @@ function testFieldAttachPrepareViewMultiple() {
 
     // Create one entity in each bundle.
     $entity1_init = field_test_create_entity(1, 1, 'test_bundle');
-    $values1 = $this->_generateTestFieldValues($this->field['cardinality']);
+    $values1 = $this->_generateTestFieldValues($this->field->cardinality);
     $entity1_init->{$this->field_name}[$langcode] = $values1;
 
     $entity2_init = field_test_create_entity(2, 2, 'test_bundle_2');
-    $values2 = $this->_generateTestFieldValues($this->field['cardinality']);
+    $values2 = $this->_generateTestFieldValues($this->field->cardinality);
     $entity2_init->{$this->field_name}[$langcode] = $values2;
 
     // Run prepare_view, and check that the entities come out as expected.
@@ -237,9 +237,9 @@ function testFieldAttachPrepareViewMultiple() {
    */
   function testFieldAttachCache() {
     // Initialize random values and a test entity.
-    $entity_init = field_test_create_entity(1, 1, $this->instance['bundle']);
+    $entity_init = field_test_create_entity(1, 1, $this->instance->bundle);
     $langcode = Language::LANGCODE_NOT_SPECIFIED;
-    $values = $this->_generateTestFieldValues($this->field['cardinality']);
+    $values = $this->_generateTestFieldValues($this->field->cardinality);
 
     // Non-cacheable entity type.
     $entity_type = 'test_entity';
@@ -265,11 +265,11 @@ function testFieldAttachCache() {
     $entity_init = entity_create($entity_type, array(
       'ftid' => 1,
       'ftvid' => 1,
-      'fttype' => $this->instance['bundle'],
+      'fttype' => $this->instance->bundle,
     ));
     $cid = "field:$entity_type:{$entity_init->ftid}";
     $instance = $this->instance;
-    $instance['entity_type'] = $entity_type;
+    $instance->entity_type = $entity_type;
     field_create_instance($instance);
 
     // Check that no initial cache entry is present.
@@ -294,7 +294,7 @@ function testFieldAttachCache() {
     $this->assertEqual($cache->data[$this->field_name][$langcode], $values, 'Cached: correct cache entry on load');
 
     // Update with different values, and check that the cache entry is wiped.
-    $values = $this->_generateTestFieldValues($this->field['cardinality']);
+    $values = $this->_generateTestFieldValues($this->field->cardinality);
     $entity = clone($entity_init);
     $entity->{$this->field_name}[$langcode] = $values;
     field_attach_update($entity);
@@ -310,9 +310,9 @@ function testFieldAttachCache() {
     $entity_init = entity_create($entity_type, array(
       'ftid' => 1,
       'ftvid' => 2,
-      'fttype' => $this->instance['bundle'],
+      'fttype' => $this->instance->bundle,
     ));
-    $values = $this->_generateTestFieldValues($this->field['cardinality']);
+    $values = $this->_generateTestFieldValues($this->field->cardinality);
     $entity = clone($entity_init);
     $entity->{$this->field_name}[$langcode] = $values;
     field_attach_update($entity);
@@ -340,12 +340,12 @@ function testFieldAttachValidate() {
     $this->createFieldWithInstance('_2');
 
     $entity_type = 'test_entity';
-    $entity = field_test_create_entity(0, 0, $this->instance['bundle']);
+    $entity = field_test_create_entity(0, 0, $this->instance->bundle);
     $langcode = Language::LANGCODE_NOT_SPECIFIED;
 
     // Set up all but one values of the first field to generate errors.
     $values = array();
-    for ($delta = 0; $delta < $this->field['cardinality']; $delta++) {
+    for ($delta = 0; $delta < $this->field->cardinality; $delta++) {
       $values[$delta]['value'] = -1;
     }
     // Arrange for item 1 not to generate an error.
@@ -354,7 +354,7 @@ function testFieldAttachValidate() {
 
     // Set up all values of the second field to generate errors.
     $values_2 = array();
-    for ($delta = 0; $delta < $this->field_2['cardinality']; $delta++) {
+    for ($delta = 0; $delta < $this->field_2->cardinality; $delta++) {
       $values_2[$delta]['value'] = -1;
     }
     $entity->{$this->field_name_2}[$langcode] = $values_2;
@@ -403,7 +403,7 @@ function testFieldAttachValidate() {
     $this->assertEqual(count($errors[$this->field_name_2][$langcode]), 0, 'No extraneous errors set for second field');
 
     // Check that cardinality is validated.
-    $entity->{$this->field_name_2}[$langcode] = $this->_generateTestFieldValues($this->field_2['cardinality'] + 1);
+    $entity->{$this->field_name_2}[$langcode] = $this->_generateTestFieldValues($this->field_2->cardinality + 1);
     // When validating all fields.
     try {
       field_attach_validate($entity);
@@ -432,22 +432,22 @@ function testFieldAttachForm() {
     $this->createFieldWithInstance('_2');
 
     $entity_type = 'test_entity';
-    $entity = field_test_create_entity(0, 0, $this->instance['bundle']);
+    $entity = field_test_create_entity(0, 0, $this->instance->bundle);
     $langcode = Language::LANGCODE_NOT_SPECIFIED;
 
     // When generating form for all fields.
     $form = array();
     $form_state = form_state_defaults();
-    $form_state['form_display'] = entity_get_form_display($entity_type, $this->instance['bundle'], 'default');
+    $form_state['form_display'] = entity_get_form_display($entity_type, $this->instance->bundle, 'default');
     field_attach_form($entity, $form, $form_state);
 
-    $this->assertEqual($form[$this->field_name][$langcode]['#title'], $this->instance['label'], "First field's form title is {$this->instance['label']}");
-    $this->assertEqual($form[$this->field_name_2][$langcode]['#title'], $this->instance_2['label'], "Second field's form title is {$this->instance_2['label']}");
-    for ($delta = 0; $delta < $this->field['cardinality']; $delta++) {
+    $this->assertEqual($form[$this->field_name][$langcode]['#title'], $this->instance->label(), "First field's form title is {$this->instance->label()}");
+    $this->assertEqual($form[$this->field_name_2][$langcode]['#title'], $this->instance_2->label(), "Second field's form title is {$this->instance_2->label()}");
+    for ($delta = 0; $delta < $this->field->cardinality; $delta++) {
       // field_test_widget uses 'textfield'
       $this->assertEqual($form[$this->field_name][$langcode][$delta]['value']['#type'], 'textfield', "First field's form delta $delta widget is textfield");
     }
-    for ($delta = 0; $delta < $this->field_2['cardinality']; $delta++) {
+    for ($delta = 0; $delta < $this->field_2->cardinality; $delta++) {
       // field_test_widget uses 'textfield'
       $this->assertEqual($form[$this->field_name_2][$langcode][$delta]['value']['#type'], 'textfield', "Second field's form delta $delta widget is textfield");
     }
@@ -456,12 +456,12 @@ function testFieldAttachForm() {
     $options = array('field_name' => $this->field_name_2);
     $form = array();
     $form_state = form_state_defaults();
-    $form_state['form_display'] = entity_get_form_display($entity_type, $this->instance['bundle'], 'default');
+    $form_state['form_display'] = entity_get_form_display($entity_type, $this->instance->bundle, 'default');
     field_attach_form($entity, $form, $form_state, NULL, $options);
 
     $this->assertFalse(isset($form[$this->field_name]), 'The first field does not exist in the form');
     $this->assertEqual($form[$this->field_name_2][$langcode]['#title'], $this->instance_2['label'], "Second field's form title is {$this->instance_2['label']}");
-    for ($delta = 0; $delta < $this->field_2['cardinality']; $delta++) {
+    for ($delta = 0; $delta < $this->field_2->cardinality; $delta++) {
       // field_test_widget uses 'textfield'
       $this->assertEqual($form[$this->field_name_2][$langcode][$delta]['value']['#type'], 'textfield', "Second field's form delta $delta widget is textfield");
     }
@@ -474,24 +474,24 @@ function testFieldAttachExtractFormValues() {
     $this->createFieldWithInstance('_2');
 
     $entity_type = 'test_entity';
-    $entity_init = field_test_create_entity(0, 0, $this->instance['bundle']);
+    $entity_init = field_test_create_entity(0, 0, $this->instance->bundle);
     $langcode = Language::LANGCODE_NOT_SPECIFIED;
 
     // Build the form for all fields.
     $form = array();
     $form_state = form_state_defaults();
-    $form_state['form_display'] = entity_get_form_display($entity_type, $this->instance['bundle'], 'default');
+    $form_state['form_display'] = entity_get_form_display($entity_type, $this->instance->bundle, 'default');
     field_attach_form($entity_init, $form, $form_state);
 
     // Simulate incoming values.
     // First field.
     $values = array();
     $weights = array();
-    for ($delta = 0; $delta < $this->field['cardinality']; $delta++) {
+    for ($delta = 0; $delta < $this->field->cardinality; $delta++) {
       $values[$delta]['value'] = mt_rand(1, 127);
       // Assign random weight.
       do {
-        $weight = mt_rand(0, $this->field['cardinality']);
+        $weight = mt_rand(0, $this->field->cardinality);
       } while (in_array($weight, $weights));
       $weights[$delta] = $weight;
       $values[$delta]['_weight'] = $weight;
@@ -501,11 +501,11 @@ function testFieldAttachExtractFormValues() {
     // Second field.
     $values_2 = array();
     $weights_2 = array();
-    for ($delta = 0; $delta < $this->field_2['cardinality']; $delta++) {
+    for ($delta = 0; $delta < $this->field_2->cardinality; $delta++) {
       $values_2[$delta]['value'] = mt_rand(1, 127);
       // Assign random weight.
       do {
-        $weight = mt_rand(0, $this->field_2['cardinality']);
+        $weight = mt_rand(0, $this->field_2->cardinality);
       } while (in_array($weight, $weights_2));
       $weights_2[$delta] = $weight;
       $values_2[$delta]['_weight'] = $weight;
diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldAttachStorageTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldAttachStorageTest.php
index 7192067..b16fb79 100644
--- a/core/modules/field/lib/Drupal/field/Tests/FieldAttachStorageTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/FieldAttachStorageTest.php
@@ -38,7 +38,7 @@ public function setUp() {
   function testFieldAttachSaveLoad() {
     // Configure the instance so that we test hook_field_load() (see
     // field_test_field_load() in field_test.module).
-    $this->instance['settings']['test_hook_field_load'] = TRUE;
+    $this->instance->settings['test_hook_field_load'] = TRUE;
     field_update_instance($this->instance);
     $langcode = Language::LANGCODE_NOT_SPECIFIED;
 
@@ -49,9 +49,9 @@ function testFieldAttachSaveLoad() {
 
     // Preparation: create three revisions and store them in $revision array.
     for ($revision_id = 0; $revision_id < 3; $revision_id++) {
-      $revision[$revision_id] = field_test_create_entity(0, $revision_id, $this->instance['bundle']);
+      $revision[$revision_id] = field_test_create_entity(0, $revision_id, $this->instance->bundle);
       // Note: we try to insert one extra value.
-      $values[$revision_id] = $this->_generateTestFieldValues($this->field['cardinality'] + 1);
+      $values[$revision_id] = $this->_generateTestFieldValues($this->field->cardinality + 1);
       $current_revision = $revision_id;
       // If this is the first revision do an insert.
       if (!$revision_id) {
@@ -66,11 +66,11 @@ function testFieldAttachSaveLoad() {
     }
 
     // Confirm current revision loads the correct data.
-    $entity = field_test_create_entity(0, 0, $this->instance['bundle']);
+    $entity = field_test_create_entity(0, 0, $this->instance->bundle);
     field_attach_load($entity_type, array(0 => $entity));
     // Number of values per field loaded equals the field cardinality.
-    $this->assertEqual(count($entity->{$this->field_name}[$langcode]), $this->field['cardinality'], 'Current revision: expected number of values');
-    for ($delta = 0; $delta < $this->field['cardinality']; $delta++) {
+    $this->assertEqual(count($entity->{$this->field_name}[$langcode]), $this->field->cardinality, 'Current revision: expected number of values');
+    for ($delta = 0; $delta < $this->field->cardinality; $delta++) {
       // The field value loaded matches the one inserted or updated.
       $this->assertEqual($entity->{$this->field_name}[$langcode][$delta]['value'] , $values[$current_revision][$delta]['value'], format_string('Current revision: expected value %delta was found.', array('%delta' => $delta)));
       // The value added in hook_field_load() is found.
@@ -79,11 +79,11 @@ function testFieldAttachSaveLoad() {
 
     // Confirm each revision loads the correct data.
     foreach (array_keys($revision) as $revision_id) {
-      $entity = field_test_create_entity(0, $revision_id, $this->instance['bundle']);
+      $entity = field_test_create_entity(0, $revision_id, $this->instance->bundle);
       field_attach_load_revision($entity_type, array(0 => $entity));
       // Number of values per field loaded equals the field cardinality.
-      $this->assertEqual(count($entity->{$this->field_name}[$langcode]), $this->field['cardinality'], format_string('Revision %revision_id: expected number of values.', array('%revision_id' => $revision_id)));
-      for ($delta = 0; $delta < $this->field['cardinality']; $delta++) {
+      $this->assertEqual(count($entity->{$this->field_name}[$langcode]), $this->field->cardinality, format_string('Revision %revision_id: expected number of values.', array('%revision_id' => $revision_id)));
+      for ($delta = 0; $delta < $this->field->cardinality; $delta++) {
         // The field value loaded matches the one inserted or updated.
         $this->assertEqual($entity->{$this->field_name}[$langcode][$delta]['value'], $values[$revision_id][$delta]['value'], format_string('Revision %revision_id: expected value %delta was found.', array('%revision_id' => $revision_id, '%delta' => $delta)));
         // The value added in hook_field_load() is found.
@@ -119,7 +119,7 @@ function testFieldAttachLoadMultiple() {
       $field_names[$i] = 'field_' . $i;
       $field = array('field_name' => $field_names[$i], 'type' => 'test_field');
       $field = field_create_field($field);
-      $field_ids[$i] = $field['uuid'];
+      $field_ids[$i] = $field->uuid;
       foreach ($field_bundles_map[$i] as $bundle) {
         $instance = array(
           'field_name' => $field_names[$i],
@@ -193,7 +193,7 @@ function testFieldAttachSaveLoadDifferentStorage() {
     foreach ($fields as $field) {
       field_create_field($field);
       $instance = array(
-        'field_name' => $field['field_name'],
+        'field_name' => $field->id(),
         'entity_type' => 'test_entity',
         'bundle' => 'test_bundle',
       );
@@ -206,8 +206,8 @@ function testFieldAttachSaveLoadDifferentStorage() {
     $entity = clone($entity_init);
     $values = array();
     foreach ($fields as $field) {
-      $values[$field['field_name']] = $this->_generateTestFieldValues($this->field['cardinality']);
-      $entity->{$field['field_name']}[$langcode] = $values[$field['field_name']];
+      $values[$field->id()] = $this->_generateTestFieldValues($this->field->cardinality);
+      $entity->{$field->id()}[$langcode] = $values[$field->id()];
     }
     field_attach_insert($entity);
 
@@ -215,7 +215,7 @@ function testFieldAttachSaveLoadDifferentStorage() {
     $entity = clone($entity_init);
     field_attach_load($entity_type, array($entity->ftid => $entity));
     foreach ($fields as $field) {
-      $this->assertEqual($values[$field['field_name']], $entity->{$field['field_name']}[$langcode], format_string('%storage storage: expected values were found.', array('%storage' => $field['storage']['type'])));
+      $this->assertEqual($values[$field->id()], $entity->{$field->id()}[$langcode], format_string('%storage storage: expected values were found.', array('%storage' => $field->storage['type'])));
     }
   }
 
@@ -240,13 +240,14 @@ function testFieldStorageDetailsAlter() {
     );
     field_create_instance($instance);
 
-    $field = field_info_field($instance['field_name']);
-    $instance = field_info_instance($instance['entity_type'], $instance['field_name'], $instance['bundle']);
+    $field = field_info_field($instance->getFieldName());
+    $instance = field_info_instance($instance->entity_type, $instance->getFieldName(), $instance->bundle);
 
     // The storage details are indexed by a storage engine type.
-    $this->assertTrue(array_key_exists('drupal_variables', $field['storage_details']), 'The storage type is Drupal variables.');
+    $this->assertTrue(array_key_exists('drupal_variables', $field->getStorageDetails()), 'The storage type is Drupal variables.');
 
-    $details = $field['storage_details']['drupal_variables'];
+    $storage_details = $field->getStorageDetails();
+    $details = $storage_details['drupal_variables'];
 
     // The field_test storage details are indexed by variable name. The details
     // are altered, so moon and mars are correct for this test.
@@ -255,7 +256,7 @@ function testFieldStorageDetailsAlter() {
 
     // Test current and revision storage details together because the columns
     // are the same.
-    foreach ($field['columns'] as $column_name => $attributes) {
+    foreach ($field->getSchema('columns') as $column_name => $attributes) {
       $this->assertEqual($details[FIELD_LOAD_CURRENT]['moon'][$column_name], $column_name, format_string('Column name %value matches the definition in %bin.', array('%value' => $column_name, '%bin' => 'moon[FIELD_LOAD_CURRENT]')));
       $this->assertEqual($details[FIELD_LOAD_REVISION]['mars'][$column_name], $column_name, format_string('Column name %value matches the definition in %bin.', array('%value' => $column_name, '%bin' => 'mars[FIELD_LOAD_REVISION]')));
     }
@@ -344,7 +345,7 @@ function testFieldAttachSaveMissingData() {
    */
   function testFieldAttachSaveMissingDataDefaultValue() {
     // Add a default value function.
-    $this->instance['default_value_function'] = 'field_test_default_value';
+    $this->instance->default_value_function = 'field_test_default_value';
     field_update_instance($this->instance);
 
     // Verify that fields are populated with default values.
@@ -386,51 +387,51 @@ function testFieldAttachSaveMissingDataDefaultValue() {
   function testFieldAttachDelete() {
     $entity_type = 'test_entity';
     $langcode = Language::LANGCODE_NOT_SPECIFIED;
-    $rev[0] = field_test_create_entity(0, 0, $this->instance['bundle']);
+    $rev[0] = field_test_create_entity(0, 0, $this->instance->bundle);
 
     // Create revision 0
-    $values = $this->_generateTestFieldValues($this->field['cardinality']);
+    $values = $this->_generateTestFieldValues($this->field->cardinality);
     $rev[0]->{$this->field_name}[$langcode] = $values;
     field_attach_insert($rev[0]);
 
     // Create revision 1
-    $rev[1] = field_test_create_entity(0, 1, $this->instance['bundle']);
+    $rev[1] = field_test_create_entity(0, 1, $this->instance->bundle);
     $rev[1]->{$this->field_name}[$langcode] = $values;
     field_attach_update($rev[1]);
 
     // Create revision 2
-    $rev[2] = field_test_create_entity(0, 2, $this->instance['bundle']);
+    $rev[2] = field_test_create_entity(0, 2, $this->instance->bundle);
     $rev[2]->{$this->field_name}[$langcode] = $values;
     field_attach_update($rev[2]);
 
     // Confirm each revision loads
     foreach (array_keys($rev) as $vid) {
-      $read = field_test_create_entity(0, $vid, $this->instance['bundle']);
+      $read = field_test_create_entity(0, $vid, $this->instance->bundle);
       field_attach_load_revision($entity_type, array(0 => $read));
-      $this->assertEqual(count($read->{$this->field_name}[$langcode]), $this->field['cardinality'], "The test entity revision $vid has {$this->field['cardinality']} values.");
+      $this->assertEqual(count($read->{$this->field_name}[$langcode]), $this->field->cardinality, "The test entity revision $vid has {$this->field->cardinality} values.");
     }
 
     // Delete revision 1, confirm the other two still load.
     field_attach_delete_revision($rev[1]);
     foreach (array(0, 2) as $vid) {
-      $read = field_test_create_entity(0, $vid, $this->instance['bundle']);
+      $read = field_test_create_entity(0, $vid, $this->instance->bundle);
       field_attach_load_revision($entity_type, array(0 => $read));
-      $this->assertEqual(count($read->{$this->field_name}[$langcode]), $this->field['cardinality'], "The test entity revision $vid has {$this->field['cardinality']} values.");
+      $this->assertEqual(count($read->{$this->field_name}[$langcode]), $this->field->cardinality, "The test entity revision $vid has {$this->field->cardinality} values.");
     }
 
     // Confirm the current revision still loads
-    $read = field_test_create_entity(0, 2, $this->instance['bundle']);
+    $read = field_test_create_entity(0, 2, $this->instance->bundle);
     field_attach_load($entity_type, array(0 => $read));
-    $this->assertEqual(count($read->{$this->field_name}[$langcode]), $this->field['cardinality'], "The test entity current revision has {$this->field['cardinality']} values.");
+    $this->assertEqual(count($read->{$this->field_name}[$langcode]), $this->field->cardinality, "The test entity current revision has {$this->field->cardinality} values.");
 
     // Delete all field data, confirm nothing loads
     field_attach_delete($rev[2]);
     foreach (array(0, 1, 2) as $vid) {
-      $read = field_test_create_entity(0, $vid, $this->instance['bundle']);
+      $read = field_test_create_entity(0, $vid, $this->instance->bundle);
       field_attach_load_revision($entity_type, array(0 => $read));
       $this->assertIdentical($read->{$this->field_name}, array(), "The test entity revision $vid is deleted.");
     }
-    $read = field_test_create_entity(0, 2, $this->instance['bundle']);
+    $read = field_test_create_entity(0, 2, $this->instance->bundle);
     field_attach_load($entity_type, array(0 => $read));
     $this->assertIdentical($read->{$this->field_name}, array(), 'The test entity current revision is deleted.');
   }
@@ -444,34 +445,34 @@ function testEntityCreateRenameBundle() {
     field_test_create_bundle($new_bundle);
 
     // Add an instance to that bundle.
-    $this->instance['bundle'] = $new_bundle;
+    $this->instance->bundle = $new_bundle;
     field_create_instance($this->instance);
 
     // Save an entity with data in the field.
-    $entity = field_test_create_entity(0, 0, $this->instance['bundle']);
+    $entity = field_test_create_entity(0, 0, $this->instance->bundle);
     $langcode = Language::LANGCODE_NOT_SPECIFIED;
-    $values = $this->_generateTestFieldValues($this->field['cardinality']);
+    $values = $this->_generateTestFieldValues($this->field->cardinality);
     $entity->{$this->field_name}[$langcode] = $values;
     $entity_type = 'test_entity';
     field_attach_insert($entity);
 
     // Verify the field data is present on load.
-    $entity = field_test_create_entity(0, 0, $this->instance['bundle']);
+    $entity = field_test_create_entity(0, 0, $this->instance->bundle);
     field_attach_load($entity_type, array(0 => $entity));
-    $this->assertEqual(count($entity->{$this->field_name}[$langcode]), $this->field['cardinality'], "Data is retrieved for the new bundle");
+    $this->assertEqual(count($entity->{$this->field_name}[$langcode]), $this->field->cardinality, "Data is retrieved for the new bundle");
 
     // Rename the bundle.
     $new_bundle = 'test_bundle_' . drupal_strtolower($this->randomName());
-    field_test_rename_bundle($this->instance['bundle'], $new_bundle);
+    field_test_rename_bundle($this->instance->bundle, $new_bundle);
 
     // Check that the instance definition has been updated.
     $this->instance = field_info_instance($entity_type, $this->field_name, $new_bundle);
-    $this->assertIdentical($this->instance['bundle'], $new_bundle, "Bundle name has been updated in the instance.");
+    $this->assertIdentical($this->instance->bundle, $new_bundle, "Bundle name has been updated in the instance.");
 
     // Verify the field data is present on load.
     $entity = field_test_create_entity(0, 0, $new_bundle);
     field_attach_load($entity_type, array(0 => $entity));
-    $this->assertEqual(count($entity->{$this->field_name}[$langcode]), $this->field['cardinality'], "Bundle name has been updated in the field storage");
+    $this->assertEqual(count($entity->{$this->field_name}[$langcode]), $this->field->cardinality, "Bundle name has been updated in the field storage");
   }
 
   /**
@@ -483,7 +484,7 @@ function testEntityDeleteBundle() {
     field_test_create_bundle($new_bundle);
 
     // Add an instance to that bundle.
-    $this->instance['bundle'] = $new_bundle;
+    $this->instance->bundle = $new_bundle;
     field_create_instance($this->instance);
 
     // Create a second field for the test bundle
@@ -493,7 +494,7 @@ function testEntityDeleteBundle() {
     $instance = array(
       'field_name' => $field_name,
       'entity_type' => 'test_entity',
-      'bundle' => $this->instance['bundle'],
+      'bundle' => $this->instance->bundle,
       'label' => $this->randomName() . '_label',
       'description' => $this->randomName() . '_description',
       'weight' => mt_rand(0, 127),
@@ -501,30 +502,30 @@ function testEntityDeleteBundle() {
     field_create_instance($instance);
 
     // Save an entity with data for both fields
-    $entity = field_test_create_entity(0, 0, $this->instance['bundle']);
+    $entity = field_test_create_entity(0, 0, $this->instance->bundle);
     $langcode = Language::LANGCODE_NOT_SPECIFIED;
-    $values = $this->_generateTestFieldValues($this->field['cardinality']);
+    $values = $this->_generateTestFieldValues($this->field->cardinality);
     $entity->{$this->field_name}[$langcode] = $values;
     $entity->{$field_name}[$langcode] = $this->_generateTestFieldValues(1);
     field_attach_insert($entity);
 
     // Verify the fields are present on load
-    $entity = field_test_create_entity(0, 0, $this->instance['bundle']);
+    $entity = field_test_create_entity(0, 0, $this->instance->bundle);
     field_attach_load('test_entity', array(0 => $entity));
     $this->assertEqual(count($entity->{$this->field_name}[$langcode]), 4, 'First field got loaded');
     $this->assertEqual(count($entity->{$field_name}[$langcode]), 1, 'Second field got loaded');
 
     // Delete the bundle.
-    field_test_delete_bundle($this->instance['bundle']);
+    field_test_delete_bundle($this->instance->bundle);
 
     // Verify no data gets loaded
-    $entity = field_test_create_entity(0, 0, $this->instance['bundle']);
+    $entity = field_test_create_entity(0, 0, $this->instance->bundle);
     field_attach_load('test_entity', array(0 => $entity));
     $this->assertFalse(isset($entity->{$this->field_name}[$langcode]), 'No data for first field');
     $this->assertFalse(isset($entity->{$field_name}[$langcode]), 'No data for second field');
 
     // Verify that the instances are gone
-    $this->assertFalse(field_read_instance('test_entity', $this->field_name, $this->instance['bundle']), "First field is deleted");
-    $this->assertFalse(field_read_instance('test_entity', $field_name, $instance['bundle']), "Second field is deleted");
+    $this->assertFalse(field_read_instance('test_entity', $this->field_name, $this->instance->bundle), "First field is deleted");
+    $this->assertFalse(field_read_instance('test_entity', $field_name, $instance->bundle), "Second field is deleted");
   }
 }
diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldImportChangeTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldImportChangeTest.php
index 523687b..09bdd1f 100644
--- a/core/modules/field/lib/Drupal/field/Tests/FieldImportChangeTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/FieldImportChangeTest.php
@@ -44,7 +44,7 @@ function testImportChange() {
     // Save as files in the the staging directory.
     $instance = $active->read($instance_config_name);
     $new_label = 'Test update import field';
-    $instance['label'] = $new_label;
+    $instance->label = $new_label;
     $staging->write($instance_config_name, $instance);
 
     // Import the content of the staging directory.
@@ -52,7 +52,7 @@ function testImportChange() {
 
     // Check that the updated config was correctly imported.
     $instance = entity_load('field_instance', $instance_id);
-    $this->assertEqual($instance['label'], $new_label, 'Instance label updated');
+    $this->assertEqual($instance->label(), $new_label, 'Instance label updated');
   }
 }
 
diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldInfoTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldInfoTest.php
index dad0e54..1ab9500 100644
--- a/core/modules/field/lib/Drupal/field/Tests/FieldInfoTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/FieldInfoTest.php
@@ -58,43 +58,43 @@ function testFieldInfo() {
       'field_name' => drupal_strtolower($this->randomName()),
       'type' => 'test_field',
     );
-    field_create_field($field);
+    $field = field_create_field($field);
     $fields = field_info_fields();
     $this->assertEqual(count($fields), count($core_fields) + 1, 'One new field exists');
-    $this->assertEqual($fields[$field['field_name']]['field_name'], $field['field_name'], 'info fields contains field name');
-    $this->assertEqual($fields[$field['field_name']]['type'], $field['type'], 'info fields contains field type');
-    $this->assertEqual($fields[$field['field_name']]['module'], 'field_test', 'info fields contains field module');
+    $this->assertEqual($fields[$field->id()]->id(), $field->id(), 'info fields contains field name');
+    $this->assertEqual($fields[$field->id()]->type, $field->type, 'info fields contains field type');
+    $this->assertEqual($fields[$field->id()]->module, 'field_test', 'info fields contains field module');
     $settings = array('test_field_setting' => 'dummy test string');
     foreach ($settings as $key => $val) {
-      $this->assertEqual($fields[$field['field_name']]['settings'][$key], $val, format_string('Field setting %key has correct default value %value', array('%key' => $key, '%value' => $val)));
+      $this->assertEqual($fields[$field->id()]->settings[$key], $val, format_string('Field setting %key has correct default value %value', array('%key' => $key, '%value' => $val)));
     }
-    $this->assertEqual($fields[$field['field_name']]['cardinality'], 1, 'info fields contains cardinality 1');
-    $this->assertEqual($fields[$field['field_name']]['active'], TRUE, 'info fields contains active 1');
+    $this->assertEqual($fields[$field->id()]->cardinality, 1, 'info fields contains cardinality 1');
+    $this->assertEqual($fields[$field->id()]->active, TRUE, 'info fields contains active 1');
 
     // Create an instance, verify that it shows up
     $instance = array(
-      'field_name' => $field['field_name'],
+      'field_name' => $field->id(),
       'entity_type' => 'test_entity',
       'bundle' => 'test_bundle',
       'label' => $this->randomName(),
       'description' => $this->randomName(),
       'weight' => mt_rand(0, 127),
     );
-    field_create_instance($instance);
+    $instance = field_create_instance($instance);
 
     $info = entity_get_info('test_entity');
-    $instances = field_info_instances('test_entity', $instance['bundle']);
+    $instances = field_info_instances('test_entity', $instance->bundle);
     $this->assertEqual(count($instances), 1, format_string('One instance shows up in info when attached to a bundle on a @label.', array(
       '@label' => $info['label']
     )));
-    $this->assertTrue($instance < $instances[$instance['field_name']], 'Instance appears in info correctly');
+    $this->assertTrue(isset($instances[$instance->getFieldName()]), 'Instance appears in info correctly');
 
     // Test a valid entity type but an invalid bundle.
     $instances = field_info_instances('test_entity', 'invalid_bundle');
     $this->assertIdentical($instances, array(), "field_info_instances('test_entity', 'invalid_bundle') returns an empty array.");
 
     // Test invalid entity type and bundle.
-    $instances = field_info_instances('invalid_entity', $instance['bundle']);
+    $instances = field_info_instances('invalid_entity', $instance->bundle);
     $this->assertIdentical($instances, array(), "field_info_instances('invalid_entity', 'test_bundle') returns an empty array.");
 
     // Test invalid entity type, no bundle provided.
@@ -142,7 +142,7 @@ function testFieldPrepare() {
 
     // Check that all expected settings are in place.
     $field_type = field_info_field_types($field_definition['type']);
-    $this->assertEqual($field['settings'], $field_type['settings'], 'All expected default field settings are present.');
+    $this->assertEqual($field->settings, $field_type['settings'], 'All expected default field settings are present.');
   }
 
   /**
@@ -176,7 +176,7 @@ function testInstancePrepare() {
 
     // Check that all expected instance settings are in place.
     $field_type = field_info_field_types($field_definition['type']);
-    $this->assertEqual($instance['settings'], $field_type['instance_settings'] , 'All expected instance settings are present.');
+    $this->assertEqual($instance->settings, $field_type['instance_settings'] , 'All expected instance settings are present.');
   }
 
   /**
diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldInstanceCrudTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldInstanceCrudTest.php
index 5f9578a..00cddde 100644
--- a/core/modules/field/lib/Drupal/field/Tests/FieldInstanceCrudTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/FieldInstanceCrudTest.php
@@ -31,7 +31,7 @@ function setUp() {
     );
     field_create_field($this->field);
     $this->instance_definition = array(
-      'field_name' => $this->field['field_name'],
+      'field_name' => $this->field->id(),
       'entity_type' => 'test_entity',
       'bundle' => 'test_bundle',
     );
@@ -95,8 +95,8 @@ function testCreateFieldInstance() {
     // by the field.
     try {
       $instance = $this->instance_definition;
-      $instance['field_name'] = $field_restricted['field_name'];
-      $instance['entity_type'] = 'test_cacheable_entity';
+      $instance->id = $field_restricted['field_name'];
+      $instance->entity_type = 'test_cacheable_entity';
       field_create_instance($instance);
       $this->pass(t('Can create an instance on an entity type allowed by the field.'));
     }
@@ -108,7 +108,7 @@ function testCreateFieldInstance() {
     // forbidden by the field.
     try {
       $instance = $this->instance_definition;
-      $instance['field_name'] = $field_restricted['field_name'];
+      $instance->id = $field_restricted['field_name'];
       field_create_instance($instance);
       $this->fail(t('Cannot create an instance on an entity type forbidden by the field.'));
     }
@@ -127,9 +127,9 @@ function testReadFieldInstance() {
 
     // Read the instance back.
     $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
-    $this->assertTrue($this->instance_definition['field_name'] == $instance['field_name'], 'The field was properly read.');
-    $this->assertTrue($this->instance_definition['entity_type'] == $instance['entity_type'], 'The field was properly read.');
-    $this->assertTrue($this->instance_definition['bundle'] == $instance['bundle'], 'The field was properly read.');
+    $this->assertTrue($this->instance_definition['field_name'] == $instance->getFieldName(), 'The field was properly read.');
+    $this->assertTrue($this->instance_definition['entity_type'] == $instance->entity_type, 'The field was properly read.');
+    $this->assertTrue($this->instance_definition['bundle'] == $instance->bundle, 'The field was properly read.');
   }
 
   /**
@@ -140,16 +140,16 @@ function testUpdateFieldInstance() {
 
     // Check that basic changes are saved.
     $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
-    $instance['required'] = !$instance['required'];
-    $instance['label'] = $this->randomName();
-    $instance['description'] = $this->randomName();
-    $instance['settings']['test_instance_setting'] = $this->randomName();
+    $instance->required = !$instance->required;
+    $instance->label = $this->randomName();
+    $instance->description = $this->randomName();
+    $instance->settings['test_instance_setting'] = $this->randomName();
     field_update_instance($instance);
 
     $instance_new = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
-    $this->assertEqual($instance['required'], $instance_new['required'], '"required" change is saved');
-    $this->assertEqual($instance['label'], $instance_new['label'], '"label" change is saved');
-    $this->assertEqual($instance['description'], $instance_new['description'], '"description" change is saved');
+    $this->assertEqual($instance->required, $instance_new->required, '"required" change is saved');
+    $this->assertEqual($instance->label(), $instance_new->label(), '"label" change is saved');
+    $this->assertEqual($instance->description, $instance_new->description, '"description" change is saved');
 
     // TODO: test failures.
   }
@@ -171,13 +171,13 @@ function testDeleteFieldInstance() {
 
     // Test that the first instance is not deleted, and then delete it.
     $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle'], array('include_deleted' => TRUE));
-    $this->assertTrue(!empty($instance) && empty($instance['deleted']), 'A new field instance is not marked for deletion.');
+    $this->assertTrue(!empty($instance) && empty($instance->deleted), 'A new field instance is not marked for deletion.');
     field_delete_instance($instance);
 
     // Make sure the instance is marked as deleted when the instance is
     // specifically loaded.
     $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle'], array('include_deleted' => TRUE));
-    $this->assertTrue(!empty($instance['deleted']), 'A deleted field instance is marked for deletion.');
+    $this->assertTrue(!empty($instance->deleted), 'A deleted field instance is marked for deletion.');
 
     // Try to load the instance normally and make sure it does not show up.
     $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
@@ -185,13 +185,13 @@ function testDeleteFieldInstance() {
 
     // Make sure the other field instance is not deleted.
     $another_instance = field_read_instance('test_entity', $this->another_instance_definition['field_name'], $this->another_instance_definition['bundle']);
-    $this->assertTrue(!empty($another_instance) && empty($another_instance['deleted']), 'A non-deleted field instance is not marked for deletion.');
+    $this->assertTrue(!empty($another_instance) && empty($another_instance->deleted), 'A non-deleted field instance is not marked for deletion.');
 
     // Make sure the field is deleted when its last instance is deleted.
     field_delete_instance($another_instance);
     $deleted_fields = \Drupal::state()->get('field.field.deleted');
-    $this->assertTrue(isset($deleted_fields[$another_instance['field_id']]), 'A deleted field is marked for deletion.');
-    $field = field_read_field($another_instance['field_name']);
+    $this->assertTrue(isset($deleted_fields[$another_instance->field_uuid]), 'A deleted field is marked for deletion.');
+    $field = field_read_field($another_instance->getFieldName());
     $this->assertFalse($field, 'The field marked to be deleted is not found anymore in the configuration.');
   }
 }
diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldUnitTestBase.php b/core/modules/field/lib/Drupal/field/Tests/FieldUnitTestBase.php
index ed3c151..33b1277 100644
--- a/core/modules/field/lib/Drupal/field/Tests/FieldUnitTestBase.php
+++ b/core/modules/field/lib/Drupal/field/Tests/FieldUnitTestBase.php
@@ -58,7 +58,7 @@ function createFieldWithInstance($suffix = '') {
     $this->$field_name = drupal_strtolower($this->randomName() . '_field_name' . $suffix);
     $this->$field = array('field_name' => $this->$field_name, 'type' => 'test_field', 'cardinality' => 4);
     $this->$field = field_create_field($this->$field);
-    $this->$field_id = $this->{$field}['uuid'];
+    $this->$field_id = $this->{$field}->uuid;
     $this->$instance = array(
       'field_name' => $this->$field_name,
       'entity_type' => 'test_entity',
diff --git a/core/modules/field/lib/Drupal/field/Tests/FormTest.php b/core/modules/field/lib/Drupal/field/Tests/FormTest.php
index 6e20523..8a0ccab 100644
--- a/core/modules/field/lib/Drupal/field/Tests/FormTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/FormTest.php
@@ -51,11 +51,11 @@ function setUp() {
 
   function testFieldFormSingle() {
     $this->field = $this->field_single;
-    $this->field_name = $this->field['field_name'];
-    $this->instance['field_name'] = $this->field_name;
+    $this->field_name = $this->field->id();
+    $this->instance->id = $this->field_name;
     field_create_field($this->field);
     field_create_instance($this->instance);
-    entity_get_form_display($this->instance['entity_type'], $this->instance['bundle'], 'default')
+    entity_get_form_display($this->instance->entity_type, $this->instance->bundle, 'default')
       ->setComponent($this->field_name)
       ->save();
     $langcode = Language::LANGCODE_NOT_SPECIFIED;
@@ -76,7 +76,7 @@ function testFieldFormSingle() {
     // Submit with invalid value (field-level validation).
     $edit = array("{$this->field_name}[$langcode][0][value]" => -1);
     $this->drupalPost(NULL, $edit, t('Save'));
-    $this->assertRaw(t('%name does not accept the value -1.', array('%name' => $this->instance['label'])), 'Field validation fails with invalid input.');
+    $this->assertRaw(t('%name does not accept the value -1.', array('%name' => $this->instance->label())), 'Field validation fails with invalid input.');
     // TODO : check that the correct field is flagged for error.
 
     // Create an entity
@@ -118,13 +118,13 @@ function testFieldFormSingle() {
    */
   function testFieldFormDefaultValue() {
     $this->field = $this->field_single;
-    $this->field_name = $this->field['field_name'];
-    $this->instance['field_name'] = $this->field_name;
+    $this->field_name = $this->field->id();
+    $this->instance->id = $this->field_name;
     $default = rand(1, 127);
-    $this->instance['default_value'] = array(array('value' => $default));
+    $this->instance->default_value = array(array('value' => $default));
     field_create_field($this->field);
     field_create_instance($this->instance);
-    entity_get_form_display($this->instance['entity_type'], $this->instance['bundle'], 'default')
+    entity_get_form_display($this->instance->entity_type, $this->instance->bundle, 'default')
       ->setComponent($this->field_name)
       ->save();
     $langcode = Language::LANGCODE_NOT_SPECIFIED;
@@ -146,12 +146,12 @@ function testFieldFormDefaultValue() {
 
   function testFieldFormSingleRequired() {
     $this->field = $this->field_single;
-    $this->field_name = $this->field['field_name'];
-    $this->instance['field_name'] = $this->field_name;
-    $this->instance['required'] = TRUE;
+    $this->field_name = $this->field->id();
+    $this->instance->id = $this->field_name;
+    $this->instance->required = TRUE;
     field_create_field($this->field);
     field_create_instance($this->instance);
-    entity_get_form_display($this->instance['entity_type'], $this->instance['bundle'], 'default')
+    entity_get_form_display($this->instance->entity_type, $this->instance->bundle, 'default')
       ->setComponent($this->field_name)
       ->save();
     $langcode = Language::LANGCODE_NOT_SPECIFIED;
@@ -159,7 +159,7 @@ function testFieldFormSingleRequired() {
     // Submit with missing required value.
     $edit = array();
     $this->drupalPost('test-entity/add/test_bundle', $edit, t('Save'));
-    $this->assertRaw(t('!name field is required.', array('!name' => $this->instance['label'])), 'Required field with no value fails validation');
+    $this->assertRaw(t('!name field is required.', array('!name' => $this->instance->label())), 'Required field with no value fails validation');
 
     // Create an entity
     $value = mt_rand(1, 127);
@@ -175,24 +175,24 @@ function testFieldFormSingleRequired() {
     $value = '';
     $edit = array("{$this->field_name}[$langcode][0][value]" => $value);
     $this->drupalPost('test-entity/manage/' . $id . '/edit', $edit, t('Save'));
-    $this->assertRaw(t('!name field is required.', array('!name' => $this->instance['label'])), 'Required field with no value fails validation');
+    $this->assertRaw(t('!name field is required.', array('!name' => $this->instance->label())), 'Required field with no value fails validation');
   }
 
 //  function testFieldFormMultiple() {
 //    $this->field = $this->field_multiple;
-//    $this->field_name = $this->field['field_name'];
-//    $this->instance['field_name'] = $this->field_name;
+//    $this->field_name = $this->field->id();
+//    $this->instance->id = $this->field_name;
 //    field_create_field($this->field);
 //    field_create_instance($this->instance);
 //  }
 
   function testFieldFormUnlimited() {
     $this->field = $this->field_unlimited;
-    $this->field_name = $this->field['field_name'];
-    $this->instance['field_name'] = $this->field_name;
+    $this->field_name = $this->field->id();
+    $this->instance->id = $this->field_name;
     field_create_field($this->field);
     field_create_instance($this->instance);
-    entity_get_form_display($this->instance['entity_type'], $this->instance['bundle'], 'default')
+    entity_get_form_display($this->instance->entity_type, $this->instance->bundle, 'default')
       ->setComponent($this->field_name)
       ->save();
     $langcode = Language::LANGCODE_NOT_SPECIFIED;
@@ -271,11 +271,11 @@ function testFieldFormUnlimited() {
   function testFieldFormMultivalueWithRequiredRadio() {
     // Create a multivalue test field.
     $this->field = $this->field_unlimited;
-    $this->field_name = $this->field['field_name'];
-    $this->instance['field_name'] = $this->field_name;
+    $this->field_name = $this->field->id();
+    $this->instance->id = $this->field_name;
     field_create_field($this->field);
     field_create_instance($this->instance);
-    entity_get_form_display($this->instance['entity_type'], $this->instance['bundle'], 'default')
+    entity_get_form_display($this->instance->entity_type, $this->instance->bundle, 'default')
       ->setComponent($this->field_name)
       ->save();
     $langcode = Language::LANGCODE_NOT_SPECIFIED;
@@ -295,8 +295,8 @@ function testFieldFormMultivalueWithRequiredRadio() {
       'required' => TRUE,
     );
     field_create_instance($instance);
-    entity_get_form_display($instance['entity_type'], $instance['bundle'], 'default')
-      ->setComponent($instance['field_name'], array(
+    entity_get_form_display($instance->entity_type, $instance->bundle, 'default')
+      ->setComponent($instance->getFieldName(), array(
         'type' => 'options_buttons',
       ))
       ->save();
@@ -318,11 +318,11 @@ function testFieldFormMultivalueWithRequiredRadio() {
 
   function testFieldFormJSAddMore() {
     $this->field = $this->field_unlimited;
-    $this->field_name = $this->field['field_name'];
-    $this->instance['field_name'] = $this->field_name;
+    $this->field_name = $this->field->id();
+    $this->instance->id = $this->field_name;
     field_create_field($this->field);
     field_create_instance($this->instance);
-    entity_get_form_display($this->instance['entity_type'], $this->instance['bundle'], 'default')
+    entity_get_form_display($this->instance->entity_type, $this->instance->bundle, 'default')
       ->setComponent($this->field_name)
       ->save();
     $langcode = Language::LANGCODE_NOT_SPECIFIED;
@@ -380,11 +380,11 @@ function testFieldFormMultipleWidget() {
     // Create a field with fixed cardinality and an instance using a multiple
     // widget.
     $this->field = $this->field_multiple;
-    $this->field_name = $this->field['field_name'];
-    $this->instance['field_name'] = $this->field_name;
+    $this->field_name = $this->field->id();
+    $this->instance->id = $this->field_name;
     field_create_field($this->field);
     field_create_instance($this->instance);
-    entity_get_form_display($this->instance['entity_type'], $this->instance['bundle'], 'default')
+    entity_get_form_display($this->instance->entity_type, $this->instance->bundle, 'default')
       ->setComponent($this->field_name, array(
         'type' => 'test_field_widget_multiple',
       ))
@@ -423,12 +423,12 @@ function testFieldFormMultipleWidget() {
   function testFieldFormAccess() {
     // Create a "regular" field.
     $field = $this->field_single;
-    $field_name = $field['field_name'];
+    $field_name = $field->id();
     $instance = $this->instance;
-    $instance['field_name'] = $field_name;
+    $instance->id = $field_name;
     field_create_field($field);
     field_create_instance($instance);
-    entity_get_form_display($this->instance['entity_type'], $this->instance['bundle'], 'default')
+    entity_get_form_display($this->instance->entity_type, $this->instance->bundle, 'default')
       ->setComponent($field_name)
       ->save();
 
@@ -455,11 +455,11 @@ function testFieldFormAccess() {
     // Test that the form structure includes full information for each delta
     // apart from #access.
     $entity_type = 'test_entity';
-    $entity = field_test_create_entity(0, 0, $this->instance['bundle']);
+    $entity = field_test_create_entity(0, 0, $this->instance->bundle);
 
     $form = array();
     $form_state = form_state_defaults();
-    $form_state['form_display'] = entity_get_form_display($entity_type, $this->instance['bundle'], 'default');
+    $form_state['form_display'] = entity_get_form_display($entity_type, $this->instance->bundle, 'default');
     field_attach_form($entity, $form, $form_state);
 
     $this->assertEqual($form[$field_name_no_access][$langcode][0]['value']['#entity_type'], $entity_type, 'The correct entity type is set in the field structure.');
@@ -503,17 +503,17 @@ function testNestedFieldForm() {
     // Add two instances on the 'test_bundle'
     field_create_field($this->field_single);
     field_create_field($this->field_unlimited);
-    $this->instance['field_name'] = 'field_single';
-    $this->instance['label'] = 'Single field';
+    $this->instance->id = 'field_single';
+    $this->instance->label = 'Single field';
     field_create_instance($this->instance);
-    entity_get_form_display($this->instance['entity_type'], $this->instance['bundle'], 'default')
-      ->setComponent($this->instance['field_name'])
+    entity_get_form_display($this->instance->entity_type, $this->instance->bundle, 'default')
+      ->setComponent($this->instance->getFieldName())
       ->save();
-    $this->instance['field_name'] = 'field_unlimited';
-    $this->instance['label'] = 'Unlimited field';
+    $this->instance->id = 'field_unlimited';
+    $this->instance->label = 'Unlimited field';
     field_create_instance($this->instance);
-    entity_get_form_display($this->instance['entity_type'], $this->instance['bundle'], 'default')
-      ->setComponent($this->instance['field_name'])
+    entity_get_form_display($this->instance->entity_type, $this->instance->bundle, 'default')
+      ->setComponent($this->instance->getFieldName())
       ->save();
 
     // Create two entities.
@@ -616,13 +616,13 @@ function testNestedFieldForm() {
    */
   function testFieldFormHiddenWidget() {
     $this->field = $this->field_single;
-    $this->field_name = $this->field['field_name'];
-    $this->instance['field_name'] = $this->field_name;
-    $this->instance['default_value'] = array(0 => array('value' => 99));
+    $this->field_name = $this->field->id();
+    $this->instance->id = $this->field_name;
+    $this->instance->default_value = array(0 => array('value' => 99));
     field_create_field($this->field);
     field_create_instance($this->instance);
-    entity_get_form_display($this->instance['entity_type'], $this->instance['bundle'], 'default')
-      ->setComponent($this->instance['field_name'], array(
+    entity_get_form_display($this->instance->entity_type, $this->instance->bundle, 'default')
+      ->setComponent($this->instance->getFieldName(), array(
         'type' => 'hidden',
       ))
       ->save();
@@ -643,10 +643,10 @@ function testFieldFormHiddenWidget() {
 
     // Update the instance to remove the default value and switch to the
     // default widget.
-    $this->instance['default_value'] = NULL;
+    $this->instance->default_value = NULL;
     field_update_instance($this->instance);
-    entity_get_form_display($this->instance['entity_type'], $this->instance['bundle'], 'default')
-      ->setComponent($this->instance['field_name'], array(
+    entity_get_form_display($this->instance->entity_type, $this->instance->bundle, 'default')
+      ->setComponent($this->instance->getFieldName(), array(
         'type' => 'test_field_widget',
       ))
       ->save();
@@ -665,8 +665,8 @@ function testFieldFormHiddenWidget() {
     $this->assertEqual($entity->{$this->field_name}[$langcode][0]['value'], $value, 'Field value was updated');
 
     // Update the form display and switch to the Hidden widget again.
-    entity_get_form_display($this->instance['entity_type'], $this->instance['bundle'], 'default')
-      ->setComponent($this->instance['field_name'], array(
+    entity_get_form_display($this->instance->entity_type, $this->instance->bundle, 'default')
+      ->setComponent($this->instance->getFieldName(), array(
         'type' => 'hidden',
       ))
       ->save();
diff --git a/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php b/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php
index ae52f2e..4e45230 100644
--- a/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php
@@ -76,7 +76,7 @@ function testFieldAvailableLanguages() {
     // Test 'translatable' fieldable info.
     field_test_entity_info_translatable('test_entity', FALSE);
     $field = clone($this->field);
-    $field['field_name'] .= '_untranslatable';
+    $field->id .= '_untranslatable';
 
     // Enable field translations for the entity.
     field_test_entity_info_translatable('test_entity', TRUE);
@@ -94,7 +94,7 @@ function testFieldAvailableLanguages() {
     $this->assertFalse(in_array('en', $available_langcodes), format_string('%language was made unavailable.', array('%language' => 'en')));
 
     // Test field_available_languages() behavior for untranslatable fields.
-    $this->field['translatable'] = FALSE;
+    $this->field->translatable = FALSE;
     field_update_field($this->field);
     $available_langcodes = field_available_languages($this->entity_type, $this->field);
     $this->assertTrue(count($available_langcodes) == 1 && $available_langcodes[0] === Language::LANGCODE_NOT_SPECIFIED, 'For untranslatable fields only Language::LANGCODE_NOT_SPECIFIED is available.');
@@ -108,7 +108,7 @@ function testFieldInvoke() {
     field_test_entity_info_translatable('test_entity', TRUE);
 
     $entity_type = 'test_entity';
-    $entity = field_test_create_entity(0, 0, $this->instance['bundle']);
+    $entity = field_test_create_entity(0, 0, $this->instance->bundle);
 
     // Populate some extra languages to check if _field_invoke() correctly uses
     // the result of field_available_languages().
@@ -121,7 +121,7 @@ function testFieldInvoke() {
 
     // For each given language provide some random values.
     foreach ($langcodes as $langcode) {
-      for ($delta = 0; $delta < $this->field['cardinality']; $delta++) {
+      for ($delta = 0; $delta < $this->field->cardinality; $delta++) {
         $values[$langcode][$delta]['value'] = mt_rand(1, 127);
       }
     }
@@ -153,7 +153,7 @@ function testFieldInvokeMultiple() {
     $available_langcodes = field_available_languages($this->entity_type, $this->field);
 
     for ($id = 1; $id <= $entity_count; ++$id) {
-      $entity = field_test_create_entity($id, $id, $this->instance['bundle']);
+      $entity = field_test_create_entity($id, $id, $this->instance->bundle);
       $langcodes = $available_langcodes;
 
       // Populate some extra languages to check whether _field_invoke()
@@ -171,7 +171,7 @@ function testFieldInvokeMultiple() {
         // per-entity language suggestions work even when available field values
         // are different for each language.
         if ($i !== $id) {
-          for ($delta = 0; $delta < $this->field['cardinality']; $delta++) {
+          for ($delta = 0; $delta < $this->field->cardinality; $delta++) {
             $values[$id][$langcode][$delta]['value'] = mt_rand(1, 127);
           }
         }
@@ -224,12 +224,12 @@ function testTranslatableFieldSaveLoad() {
     field_test_entity_info_translatable('test_entity', TRUE);
     $eid = $evid = 1;
     $entity_type = 'test_entity';
-    $entity = field_test_create_entity($eid, $evid, $this->instance['bundle']);
+    $entity = field_test_create_entity($eid, $evid, $this->instance->bundle);
     $field_translations = array();
     $available_langcodes = field_available_languages($entity_type, $this->field);
     $this->assertTrue(count($available_langcodes) > 1, 'Field is translatable.');
     foreach ($available_langcodes as $langcode) {
-      $field_translations[$langcode] = $this->_generateTestFieldValues($this->field['cardinality']);
+      $field_translations[$langcode] = $this->_generateTestFieldValues($this->field->cardinality);
     }
 
     // Save and reload the field translations.
@@ -264,9 +264,9 @@ function testTranslatableFieldSaveLoad() {
 
     $eid++;
     $evid++;
-    $values = array('eid' => $eid, 'evid' => $evid, 'fttype' => $instance['bundle'], 'langcode' => $translation_langcodes[0]);
+    $values = array('eid' => $eid, 'evid' => $evid, 'fttype' => $instance->bundle, 'langcode' => $translation_langcodes[0]);
     foreach ($translation_langcodes as $langcode) {
-      $values[$this->field_name][$langcode] = $this->_generateTestFieldValues($this->field['cardinality']);
+      $values[$this->field_name][$langcode] = $this->_generateTestFieldValues($this->field->cardinality);
     }
     $entity = entity_create($entity_type, $values);
 
@@ -275,16 +275,16 @@ function testTranslatableFieldSaveLoad() {
     $this->assertEqual($translation_langcodes, $field_langcodes, 'Missing translations did not get a default value.');
 
     foreach ($entity->{$field_name_default} as $langcode => $items) {
-      $this->assertEqual($items, $instance['default_value'], format_string('Default value correctly populated for language %language.', array('%language' => $langcode)));
+      $this->assertEqual($items, $instance->default_value, format_string('Default value correctly populated for language %language.', array('%language' => $langcode)));
     }
 
     // Check that explicit empty values are not overridden with default values.
     foreach (array(NULL, array()) as $empty_items) {
       $eid++;
       $evid++;
-      $values = array('eid' => $eid, 'evid' => $evid, 'fttype' => $instance['bundle'], 'langcode' => $translation_langcodes[0]);
+      $values = array('eid' => $eid, 'evid' => $evid, 'fttype' => $instance->bundle, 'langcode' => $translation_langcodes[0]);
       foreach ($translation_langcodes as $langcode) {
-        $values[$this->field_name][$langcode] = $this->_generateTestFieldValues($this->field['cardinality']);
+        $values[$this->field_name][$langcode] = $this->_generateTestFieldValues($this->field->cardinality);
         $values[$field_name_default][$langcode] = $empty_items;
       }
       $entity = entity_create($entity_type, $values);
@@ -313,14 +313,14 @@ function testFieldDisplayLanguage() {
     field_create_field($field);
 
     $instance = array(
-      'field_name' => $field['field_name'],
+      'field_name' => $field->id(),
       'entity_type' => $entity_type,
       'bundle' => 'test_bundle',
     );
     field_create_instance($instance);
 
-    $entity = field_test_create_entity(1, 1, $this->instance['bundle']);
-    $instances = field_info_instances($entity_type, $this->instance['bundle']);
+    $entity = field_test_create_entity(1, 1, $this->instance->bundle);
+    $instances = field_info_instances($entity_type, $this->instance->bundle);
 
     $enabled_langcodes = field_content_languages();
     $langcodes = array();
@@ -331,7 +331,7 @@ function testFieldDisplayLanguage() {
     // Generate field translations for languages different from the first
     // enabled.
     foreach ($instances as $instance) {
-      $field_name = $instance['field_name'];
+      $field_name = $instance->getFieldName();
       $field = field_info_field($field_name);
       do {
         // Index 0 is reserved for the requested language, this way we ensure
@@ -340,7 +340,7 @@ function testFieldDisplayLanguage() {
       }
       while (isset($langcodes[$langcode]));
       $langcodes[$langcode] = TRUE;
-      $entity->{$field_name}[$langcode] = $this->_generateTestFieldValues($field['cardinality']);
+      $entity->{$field_name}[$langcode] = $this->_generateTestFieldValues($field->cardinality);
       // If the langcode is one of the locked languages, then that one
       // will also be used for display. Otherwise, the default one should be
       // used, which is Language::LANGCODE_NOT_SPECIFIED.
@@ -358,7 +358,7 @@ function testFieldDisplayLanguage() {
     $requested_langcode = $enabled_langcodes[0];
     $display_langcodes = field_language($entity, NULL, $requested_langcode);
     foreach ($instances as $instance) {
-      $field_name = $instance['field_name'];
+      $field_name = $instance->getFieldName();
       $this->assertTrue($display_langcodes[$field_name] == $locked_languages[$field_name], format_string('The display language for field %field_name is %language.', array('%field_name' => $field_name, '%language' => $locked_languages[$field_name])));
     }
 
@@ -367,7 +367,7 @@ function testFieldDisplayLanguage() {
     drupal_static_reset('field_language');
     $display_langcodes = field_language($entity, NULL, $requested_langcode);
     foreach ($instances as $instance) {
-      $field_name = $instance['field_name'];
+      $field_name = $instance->getFieldName();
       $langcode = $display_langcodes[$field_name];
       // As the requested language was not assinged to any field, if the
       // returned language is defined for the current field, core fallback rules
diff --git a/core/modules/field/lib/Drupal/field/Tests/TranslationWebTest.php b/core/modules/field/lib/Drupal/field/Tests/TranslationWebTest.php
index 786f1b4..db2c927 100644
--- a/core/modules/field/lib/Drupal/field/Tests/TranslationWebTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/TranslationWebTest.php
@@ -76,10 +76,10 @@ function testFieldFormTranslationRevisions() {
     // Prepare the field translations.
     field_test_entity_info_translatable($this->entity_type, TRUE);
     $eid = 1;
-    $entity = field_test_create_entity($eid, $eid, $this->instance['bundle']);
+    $entity = field_test_create_entity($eid, $eid, $this->instance->bundle);
     $available_langcodes = array_flip(field_available_languages($this->entity_type, $this->field));
     unset($available_langcodes[Language::LANGCODE_NOT_SPECIFIED]);
-    $field_name = $this->field['field_name'];
+    $field_name = $this->field->id();
 
     // Store the field translations.
     $entity->enforceIsNew();
@@ -103,7 +103,7 @@ function testFieldFormTranslationRevisions() {
    * by the passed arguments were correctly stored.
    */
   private function checkTranslationRevisions($eid, $evid, $available_langcodes) {
-    $field_name = $this->field['field_name'];
+    $field_name = $this->field->id();
     $entity = field_test_entity_test_load($eid, $evid);
     foreach ($available_langcodes as $langcode => $value) {
       $passed = isset($entity->{$field_name}[$langcode]) && $entity->{$field_name}[$langcode][0]['value'] == $value + 1;
diff --git a/core/modules/field/lib/Drupal/field/Tests/Views/FieldTestBase.php b/core/modules/field/lib/Drupal/field/Tests/Views/FieldTestBase.php
index c0f500b..788dced 100644
--- a/core/modules/field/lib/Drupal/field/Tests/Views/FieldTestBase.php
+++ b/core/modules/field/lib/Drupal/field/Tests/Views/FieldTestBase.php
@@ -66,7 +66,7 @@ function setUpFields($amount = 3) {
   function setUpInstances($bundle = 'page') {
     foreach ($this->fields as $key => $field) {
       $instance = array(
-        'field_name' => $field['field_name'],
+        'field_name' => $field->id(),
         'entity_type' => 'node',
         'bundle' => 'page',
       );
diff --git a/core/modules/field/lib/Drupal/field/Tests/Views/HandlerFieldFieldTest.php b/core/modules/field/lib/Drupal/field/Tests/Views/HandlerFieldFieldTest.php
index f365635..694ed28 100644
--- a/core/modules/field/lib/Drupal/field/Tests/Views/HandlerFieldFieldTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/Views/HandlerFieldFieldTest.php
@@ -60,13 +60,13 @@ protected function setUp() {
 
       for ($key = 0; $key < 3; $key++) {
         $field = $this->fields[$key];
-        $edit[$field['field_name']][0]['value'] = $this->randomName(8);
+        $edit[$field->id()][0]['value'] = $this->randomName(8);
       }
       for ($j = 0; $j < 5; $j++) {
-        $edit[$this->fields[3]['field_name']][$j]['value'] = $this->randomName(8);
+        $edit[$this->fields[3]->id()][$j]['value'] = $this->randomName(8);
       }
       // Set this field to be empty.
-      $edit[$this->fields[4]['field_name']] = array(array('value' => NULL));
+      $edit[$this->fields[4]->id()] = array(array('value' => NULL));
 
       $this->nodes[$i] = $this->drupalCreateNode($edit);
     }
@@ -83,9 +83,9 @@ protected function setUp() {
   protected function prepareView(ViewExecutable $view) {
     $view->initDisplay();
     foreach ($this->fields as $key => $field) {
-      $view->display_handler->options['fields'][$field['field_name']]['id'] = $field['field_name'];
-      $view->display_handler->options['fields'][$field['field_name']]['table'] = 'field_data_' . $field['field_name'];
-      $view->display_handler->options['fields'][$field['field_name']]['field'] = $field['field_name'];
+      $view->display_handler->options['fields'][$field->id()]['id'] = $field->id();
+      $view->display_handler->options['fields'][$field->id()]['table'] = 'field_data_' . $field->id();
+      $view->display_handler->options['fields'][$field->id()]['field'] = $field->id();
     }
   }
 
@@ -104,8 +104,8 @@ public function _testSimpleFieldRender() {
     for ($i = 0; $i < 3; $i++) {
       for ($key = 0; $key < 2; $key++) {
         $field = $this->fields[$key];
-        $rendered_field = $view->style_plugin->getField($i, $field['field_name']);
-        $expected_field = $this->nodes[$i]->{$field['field_name']}[Language::LANGCODE_NOT_SPECIFIED][0]['value'];
+        $rendered_field = $view->style_plugin->getField($i, $field->id());
+        $expected_field = $this->nodes[$i]->{$field->id()}[Language::LANGCODE_NOT_SPECIFIED][0]['value'];
         $this->assertEqual($rendered_field, $expected_field);
       }
     }
@@ -117,8 +117,8 @@ public function _testSimpleFieldRender() {
   public function _testFormatterSimpleFieldRender() {
     $view = views_get_view('test_view_fieldapi');
     $this->prepareView($view);
-    $view->displayHandlers->get('default')->options['fields'][$this->fields[0]['field_name']]['type'] = 'text_trimmed';
-    $view->displayHandlers->get('default')->options['fields'][$this->fields[0]['field_name']]['settings'] = array(
+    $view->displayHandlers->get('default')->options['fields'][$this->fields[0]['field_name']]->type = 'text_trimmed';
+    $view->displayHandlers->get('default')->options['fields'][$this->fields[0]['field_name']]->settings = array(
       'trim_length' => 3,
     );
     $this->executeView($view);
@@ -137,8 +137,8 @@ public function _testMultipleFieldRender() {
 
     // Test delta limit.
     $this->prepareView($view);
-    $view->displayHandlers->get('default')->options['fields'][$field_name]['group_rows'] = TRUE;
-    $view->displayHandlers->get('default')->options['fields'][$field_name]['delta_limit'] = 3;
+    $view->displayHandlers->get('default')->options['fields'][$field_name]->group_rows = TRUE;
+    $view->displayHandlers->get('default')->options['fields'][$field_name]->delta_limit = 3;
     $this->executeView($view);
 
     for ($i = 0; $i < 3; $i++) {
@@ -159,9 +159,9 @@ public function _testMultipleFieldRender() {
 
     // Test delta limit + offset
     $this->prepareView($view);
-    $view->displayHandlers->get('default')->options['fields'][$field_name]['group_rows'] = TRUE;
-    $view->displayHandlers->get('default')->options['fields'][$field_name]['delta_limit'] = 3;
-    $view->displayHandlers->get('default')->options['fields'][$field_name]['delta_offset'] = 1;
+    $view->displayHandlers->get('default')->options['fields'][$field_name]->group_rows = TRUE;
+    $view->displayHandlers->get('default')->options['fields'][$field_name]->delta_limit = 3;
+    $view->displayHandlers->get('default')->options['fields'][$field_name]->delta_offset = 1;
     $this->executeView($view);
 
     for ($i = 0; $i < 3; $i++) {
@@ -178,10 +178,10 @@ public function _testMultipleFieldRender() {
 
     // Test delta limit + reverse.
     $this->prepareView($view);
-    $view->displayHandlers->get('default')->options['fields'][$field_name]['delta_offset'] = 0;
-    $view->displayHandlers->get('default')->options['fields'][$field_name]['group_rows'] = TRUE;
-    $view->displayHandlers->get('default')->options['fields'][$field_name]['delta_limit'] = 3;
-    $view->displayHandlers->get('default')->options['fields'][$field_name]['delta_reversed'] = TRUE;
+    $view->displayHandlers->get('default')->options['fields'][$field_name]->delta_offset = 0;
+    $view->displayHandlers->get('default')->options['fields'][$field_name]->group_rows = TRUE;
+    $view->displayHandlers->get('default')->options['fields'][$field_name]->delta_limit = 3;
+    $view->displayHandlers->get('default')->options['fields'][$field_name]->delta_reversed = TRUE;
     $this->executeView($view);
 
     for ($i = 0; $i < 3; $i++) {
@@ -199,10 +199,10 @@ public function _testMultipleFieldRender() {
 
     // Test delta first last.
     $this->prepareView($view);
-    $view->displayHandlers->get('default')->options['fields'][$field_name]['group_rows'] = TRUE;
-    $view->displayHandlers->get('default')->options['fields'][$field_name]['delta_limit'] = 0;
-    $view->displayHandlers->get('default')->options['fields'][$field_name]['delta_first_last'] = TRUE;
-    $view->displayHandlers->get('default')->options['fields'][$field_name]['delta_reversed'] = FALSE;
+    $view->displayHandlers->get('default')->options['fields'][$field_name]->group_rows = TRUE;
+    $view->displayHandlers->get('default')->options['fields'][$field_name]->delta_limit = 0;
+    $view->displayHandlers->get('default')->options['fields'][$field_name]->delta_first_last = TRUE;
+    $view->displayHandlers->get('default')->options['fields'][$field_name]->delta_reversed = FALSE;
     $this->executeView($view);
 
     for ($i = 0; $i < 3; $i++) {
@@ -217,10 +217,10 @@ public function _testMultipleFieldRender() {
 
     // Test delta limit + custom seperator.
     $this->prepareView($view);
-    $view->displayHandlers->get('default')->options['fields'][$field_name]['delta_first_last'] = FALSE;
-    $view->displayHandlers->get('default')->options['fields'][$field_name]['delta_limit'] = 3;
-    $view->displayHandlers->get('default')->options['fields'][$field_name]['group_rows'] = TRUE;
-    $view->displayHandlers->get('default')->options['fields'][$field_name]['separator'] = ':';
+    $view->displayHandlers->get('default')->options['fields'][$field_name]->delta_first_last = FALSE;
+    $view->displayHandlers->get('default')->options['fields'][$field_name]->delta_limit = 3;
+    $view->displayHandlers->get('default')->options['fields'][$field_name]->group_rows = TRUE;
+    $view->displayHandlers->get('default')->options['fields'][$field_name]->separator = ':';
     $this->executeView($view);
 
     for ($i = 0; $i < 3; $i++) {
diff --git a/core/modules/field/tests/modules/field_test/field_test.field.inc b/core/modules/field/tests/modules/field_test/field_test.field.inc
index 0ff40e7..1384f17 100644
--- a/core/modules/field/tests/modules/field_test/field_test.field.inc
+++ b/core/modules/field/tests/modules/field_test/field_test.field.inc
@@ -65,7 +65,7 @@ function field_test_field_widget_info_alter(&$info) {
  * Implements hook_field_update_forbid().
  */
 function field_test_field_update_forbid($field, $prior_field) {
-  if ($field['type'] == 'test_field' && $field['settings']['unchangeable'] != $prior_field['settings']['unchangeable']) {
+  if ($field->type == 'test_field' && $field->settings['unchangeable'] != $prior_field->settings['unchangeable']) {
     throw new FieldException("field_test 'unchangeable' setting cannot be changed'");
   }
 }
@@ -80,7 +80,7 @@ function field_test_field_load($entity_type, $entities, $field, $instances, $lan
   foreach ($items as $id => $item) {
     // To keep the test non-intrusive, only act for instances with the
     // test_hook_field_load setting explicitly set to TRUE.
-    if (!empty($instances[$id]['settings']['test_hook_field_load'])) {
+    if (!empty($instances[$id]->settings['test_hook_field_load'])) {
       foreach ($item as $delta => $value) {
         // Don't add anything on empty values.
         if ($value) {
@@ -127,9 +127,9 @@ function field_test_field_validate(EntityInterface $entity = NULL, $field, $inst
 
   foreach ($items as $delta => $item) {
     if ($item['value'] == -1) {
-      $errors[$field['field_name']][$langcode][$delta][] = array(
+      $errors[$field->id()][$langcode][$delta][] = array(
         'error' => 'field_test_invalid',
-        'message' => t('%name does not accept the value -1.', array('%name' => $instance['label'])),
+        'message' => t('%name does not accept the value -1.', array('%name' => $instance->label())),
       );
     }
   }
@@ -146,7 +146,7 @@ function field_test_field_is_empty($item, $field_type) {
  * Implements hook_field_settings_form().
  */
 function field_test_field_settings_form($field, $instance) {
-  $settings = $field['settings'];
+  $settings = $field->settings;
 
   $form['test_field_setting'] = array(
     '#type' => 'textfield',
@@ -163,7 +163,7 @@ function field_test_field_settings_form($field, $instance) {
  * Implements hook_field_instance_settings_form().
  */
 function field_test_field_instance_settings_form($field, $instance) {
-  $settings = $instance['settings'];
+  $settings = $instance->settings;
 
   $form['test_instance_setting'] = array(
     '#type' => 'textfield',
@@ -199,13 +199,13 @@ function field_test_default_value(EntityInterface $entity, $field, $instance) {
  * Implements hook_field_access().
  */
 function field_test_field_access($op, FieldInterface $field, $entity_type, $entity, $account) {
-  if ($field['field_name'] == "field_no_{$op}_access") {
+  if ($field->id() == "field_no_{$op}_access") {
     return FALSE;
   }
 
   // Only grant view access to test_view_field fields when the user has
   // 'view test_view_field content' permission.
-  if ($field['field_name'] == 'test_view_field' && $op == 'view' && !user_access('view test_view_field content')) {
+  if ($field->id() == 'test_view_field' && $op == 'view' && !user_access('view test_view_field content')) {
     return FALSE;
   }
 
diff --git a/core/modules/field/tests/modules/field_test/field_test.install b/core/modules/field/tests/modules/field_test/field_test.install
index b0a15a2..8300ce9 100644
--- a/core/modules/field/tests/modules/field_test/field_test.install
+++ b/core/modules/field/tests/modules/field_test/field_test.install
@@ -114,7 +114,7 @@ function field_test_schema() {
  * Implements hook_field_schema().
  */
 function field_test_field_schema($field) {
-  if ($field['type'] == 'test_field') {
+  if ($field->type == 'test_field') {
     return array(
       'columns' => array(
         'value' => array(
@@ -131,13 +131,13 @@ function field_test_field_schema($field) {
   else {
     $foreign_keys = array();
     // The 'foreign keys' key is not always used in tests.
-    if (!empty($field['settings']['foreign_key_name'])) {
+    if (!empty($field->settings['foreign_key_name'])) {
       $foreign_keys['foreign keys'] = array(
         // This is a dummy foreign key definition, references a table that
         // doesn't exist, but that's not a problem.
-        $field['settings']['foreign_key_name'] => array(
-          'table' => $field['settings']['foreign_key_name'],
-          'columns' => array($field['settings']['foreign_key_name'] => 'id'),
+        $field->settings['foreign_key_name'] => array(
+          'table' => $field->settings['foreign_key_name'],
+          'columns' => array($field->settings['foreign_key_name'] => 'id'),
         ),
       );
     }
diff --git a/core/modules/field/tests/modules/field_test/field_test.module b/core/modules/field/tests/modules/field_test/field_test.module
index 04f1c83..74103136 100644
--- a/core/modules/field/tests/modules/field_test/field_test.module
+++ b/core/modules/field/tests/modules/field_test/field_test.module
@@ -80,7 +80,7 @@ function field_test_menu() {
  * This simulates a field operation callback to be invoked by _field_invoke().
  */
 function field_test_field_test_op(EntityInterface $entity, $field, $instance, $langcode, &$items) {
-  return array($langcode => hash('sha256', serialize(array($entity, $field['field_name'], $langcode, $items))));
+  return array($langcode => hash('sha256', serialize(array($entity, $field->id(), $langcode, $items))));
 }
 
 /**
@@ -96,7 +96,7 @@ function field_test_field_test_op_multiple($entity_type, $entities, $field, $ins
     // language. To verify this we try to access all the passed data structures
     // by entity id. If they are grouped correctly, one entity, one instance and
     // one array of items should be available for each entity id.
-    $field_name = $instances[$id]['field_name'];
+    $field_name = $instances[$id]->getFieldName();
     $result[$id] = array($langcode => hash('sha256', serialize(array($entity_type, $entity, $field_name, $langcode, $items[$id]))));
   }
   return $result;
diff --git a/core/modules/field/tests/modules/field_test/field_test.storage.inc b/core/modules/field/tests/modules/field_test/field_test.storage.inc
index d3a7f82..07b73e6 100644
--- a/core/modules/field/tests/modules/field_test/field_test.storage.inc
+++ b/core/modules/field/tests/modules/field_test/field_test.storage.inc
@@ -31,7 +31,7 @@ function field_test_field_storage_details($field) {
 
   // Add field columns.
   $columns = array();
-  foreach ((array) $field['columns'] as $column_name => $attributes) {
+  foreach ((array) $field->getSchema('columns') as $column_name => $attributes) {
     $columns[$column_name] = $column_name;
   }
   return array(
@@ -50,9 +50,9 @@ function field_test_field_storage_details($field) {
 function field_test_field_storage_details_alter(&$details, $field) {
 
   // For testing, storage details are changed only because of the field name.
-  if ($field['field_name'] == 'field_test_change_my_details') {
+  if ($field->id() == 'field_test_change_my_details') {
     $columns = array();
-    foreach ((array) $field['columns'] as $column_name => $attributes) {
+    foreach ((array) $field->getSchema('columns') as $column_name => $attributes) {
       $columns[$column_name] = $column_name;
     }
     $details['drupal_variables'] = array(
@@ -88,8 +88,8 @@ function field_test_field_storage_load($entity_type, $entities, $age, $fields, $
 
   foreach ($fields as $field_id => $ids) {
     $field = field_info_field_by_id($field_id);
-    $field_name = $field['field_name'];
-    $field_data = $data[$field['uuid']];
+    $field_name = $field->id();
+    $field_data = $data[$field->uuid];
     $sub_table = $load_current ? 'current' : 'revisions';
     $delta_count = array();
     foreach ($field_data[$sub_table] as $row) {
@@ -99,9 +99,9 @@ function field_test_field_storage_load($entity_type, $entities, $age, $fields, $
             if (!isset($delta_count[$row->entity_id][$row->langcode])) {
               $delta_count[$row->entity_id][$row->langcode] = 0;
             }
-            if ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED || $delta_count[$row->entity_id][$row->langcode] < $field['cardinality']) {
+            if ($field->cardinality == FIELD_CARDINALITY_UNLIMITED || $delta_count[$row->entity_id][$row->langcode] < $field->cardinality) {
               $item = array();
-              foreach ($field['columns'] as $column => $attributes) {
+              foreach ($field->getSchema('columns') as $column => $attributes) {
                 $item[$column] = $row->{$column};
               }
               $entities[$row->entity_id]->{$field_name}[$row->langcode][] = $item;
@@ -126,7 +126,7 @@ function field_test_field_storage_write(EntityInterface $entity, $op, $fields) {
 
   foreach ($fields as $field_id) {
     $field = field_info_field_by_id($field_id);
-    $field_name = $field['field_name'];
+    $field_name = $field->id();
     $field_data = &$data[$field_id];
 
     $all_langcodes = field_available_languages($entity->entityType(), $field);
@@ -167,7 +167,7 @@ function field_test_field_storage_write(EntityInterface $entity, $op, $fields) {
           'deleted' => FALSE,
           'langcode' => $langcode,
         );
-        foreach ($field['columns'] as $column => $attributes) {
+        foreach ($field->getSchema('columns') as $column => $attributes) {
           $row->{$column} = isset($item[$column]) ? $item[$column] : NULL;
         }
 
@@ -176,7 +176,7 @@ function field_test_field_storage_write(EntityInterface $entity, $op, $fields) {
           $field_data['revisions'][] = $row;
         }
 
-        if ($field['cardinality'] != FIELD_CARDINALITY_UNLIMITED && ++$delta_count == $field['cardinality']) {
+        if ($field->cardinality != FIELD_CARDINALITY_UNLIMITED && ++$delta_count == $field->cardinality) {
           break;
         }
       }
@@ -193,8 +193,8 @@ function field_test_field_storage_delete(EntityInterface $entity, $fields) {
   // Note: reusing field_test_storage_purge(), like field_sql_storage.module
   // does, is highly inefficient in our case...
   foreach (field_info_instances($entity->entityType(), $entity->bundle()) as $instance) {
-    if (isset($fields[$instance['field_id']])) {
-      $field = field_info_field_by_id($instance['field_id']);
+    if (isset($fields[$instance->field_uuid])) {
+      $field = field_info_field_by_id($instance->field_uuid);
       field_test_field_storage_purge($entity, $field, $instance);
     }
   }
@@ -206,7 +206,7 @@ function field_test_field_storage_delete(EntityInterface $entity, $fields) {
 function field_test_field_storage_purge(EntityInterface $entity, $field, $instance) {
   $data = _field_test_storage_data();
 
-  $field_data = &$data[$field['uuid']];
+  $field_data = &$data[$field->uuid];
   foreach (array('current', 'revisions') as $sub_table) {
     foreach ($field_data[$sub_table] as $key => $row) {
       if ($row->type == $entity->entityType() && $row->entity_id == $entity->id()) {
@@ -247,9 +247,9 @@ function field_test_field_storage_query($field_id, $conditions, $count, &$cursor
   $load_current = $age == FIELD_LOAD_CURRENT;
 
   $field = field_info_field_by_id($field_id);
-  $field_columns = array_keys($field['columns']);
+  $field_columns = array_keys($field->getSchema('columns'));
 
-  $field_data = $data[$field['uuid']];
+  $field_data = $data[$field->uuid];
   $sub_table = $load_current ? 'current' : 'revisions';
   // We need to sort records by entity type and entity id.
   usort($field_data[$sub_table], '_field_test_field_storage_query_sort_helper');
@@ -267,7 +267,7 @@ function field_test_field_storage_query($field_id, $conditions, $count, &$cursor
       break;
     }
 
-    if ($row->field_id == $field['uuid']) {
+    if ($row->field_id == $field->uuid) {
       $match = TRUE;
       $condition_deleted = FALSE;
       // Add conditions.
@@ -366,13 +366,13 @@ function _field_test_field_storage_query_sort_helper($a, $b) {
  * Implements hook_field_storage_create_field().
  */
 function field_test_field_storage_create_field($field) {
-  if ($field['storage']['type'] == 'field_test_storage_failure') {
+  if ($field->storage['type'] == 'field_test_storage_failure') {
     throw new Exception('field_test_storage_failure engine always fails to create fields');
   }
 
   $data = _field_test_storage_data();
 
-  $data[$field['uuid']] = array(
+  $data[$field->uuid] = array(
     'current' => array(),
     'revisions' => array(),
   );
@@ -386,7 +386,7 @@ function field_test_field_storage_create_field($field) {
 function field_test_field_storage_delete_field($field) {
   $data = _field_test_storage_data();
 
-  $field_data = &$data[$field['uuid']];
+  $field_data = &$data[$field->uuid];
   foreach (array('current', 'revisions') as $sub_table) {
     foreach ($field_data[$sub_table] as &$row) {
       $row->deleted = TRUE;
@@ -402,11 +402,11 @@ function field_test_field_storage_delete_field($field) {
 function field_test_field_storage_delete_instance($instance) {
   $data = _field_test_storage_data();
 
-  $field = field_info_field($instance['field_name']);
-  $field_data = &$data[$field['uuid']];
+  $field = field_info_field($instance->getFieldName());
+  $field_data = &$data[$field->uuid];
   foreach (array('current', 'revisions') as $sub_table) {
     foreach ($field_data[$sub_table] as &$row) {
-      if ($row->bundle == $instance['bundle']) {
+      if ($row->bundle == $instance->bundle) {
         $row->deleted = TRUE;
       }
     }
@@ -424,9 +424,9 @@ function field_test_entity_bundle_rename($entity_type, $bundle_old, $bundle_new)
   // We need to account for deleted or inactive fields and instances.
   $instances = field_read_instances(array('bundle' => $bundle_new), array('include_deleted' => TRUE, 'include_inactive' => TRUE));
   foreach ($instances as $field_name => $instance) {
-    $field = field_info_field_by_id($instance['field_id']);
-    if ($field && $field['storage']['type'] == 'field_test_storage') {
-      $field_data = &$data[$field['uuid']];
+    $field = field_info_field_by_id($instance->field_uuid);
+    if ($field && $field->storage['type'] == 'field_test_storage') {
+      $field_data = &$data[$field->uuid];
       foreach (array('current', 'revisions') as $sub_table) {
         foreach ($field_data[$sub_table] as &$row) {
           if ($row->bundle == $bundle_old) {
@@ -446,12 +446,12 @@ function field_test_entity_bundle_rename($entity_type, $bundle_old, $bundle_new)
 function field_test_field_delete_instance($instance) {
   $data = _field_test_storage_data();
 
-  $field = field_info_field($instance['field_name']);
-  if ($field['storage']['type'] == 'field_test_storage') {
-    $field_data = &$data[$field['uuid']];
+  $field = field_info_field($instance->getFieldName());
+  if ($field->storage['type'] == 'field_test_storage') {
+    $field_data = &$data[$field->uuid];
     foreach (array('current', 'revisions') as $sub_table) {
       foreach ($field_data[$sub_table] as &$row) {
-        if ($row->bundle == $instance['bundle']) {
+        if ($row->bundle == $instance->bundle) {
           $row->deleted = TRUE;
         }
       }
diff --git a/core/modules/field_sql_storage/field_sql_storage.module b/core/modules/field_sql_storage/field_sql_storage.module
index 3ccac54..dd0343d 100644
--- a/core/modules/field_sql_storage/field_sql_storage.module
+++ b/core/modules/field_sql_storage/field_sql_storage.module
@@ -50,11 +50,11 @@ function field_sql_storage_field_storage_info() {
  *   A string containing the generated name for the database table.
  */
 function _field_sql_storage_tablename($field) {
-  if ($field['deleted']) {
-    return "field_deleted_data_" . substr(hash('sha256', $field['uuid']), 0, 10);
+  if ($field->deleted) {
+    return "field_deleted_data_" . substr(hash('sha256', $field->uuid), 0, 10);
   }
   else {
-    return "field_data_{$field['field_name']}";
+    return "field_data_{$field->id()}";
   }
 }
 
@@ -73,11 +73,11 @@ function _field_sql_storage_tablename($field) {
  *   A string containing the generated name for the database table.
  */
 function _field_sql_storage_revision_tablename($field) {
-  if ($field['deleted']) {
-    return "field_deleted_revision_" . substr(hash('sha256', $field['uuid']), 0, 10);
+  if ($field->deleted) {
+    return "field_deleted_revision_" . substr(hash('sha256', $field->uuid), 0, 10);
   }
   else {
-    return "field_revision_{$field['field_name']}";
+    return "field_revision_{$field->id()}";
   }
 }
 
@@ -126,9 +126,9 @@ function _field_sql_storage_indexname($name, $index) {
  *   One or more tables representing the schema for the field.
  */
 function _field_sql_storage_schema($field) {
-  $deleted = $field['deleted'] ? 'deleted ' : '';
+  $deleted = $field->deleted ? 'deleted ' : '';
   $current = array(
-    'description' => "Data storage for {$deleted}field {$field['id']} ({$field['field_name']})",
+    'description' => "Data storage for {$deleted}field {$field->id()} ({$field->id()})",
     'fields' => array(
       'entity_type' => array(
         'type' => 'varchar',
@@ -193,41 +193,41 @@ function _field_sql_storage_schema($field) {
 
   // Add field columns.
   foreach ($schema['columns'] as $column_name => $attributes) {
-    $real_name = _field_sql_storage_columnname($field['field_name'], $column_name);
+    $real_name = _field_sql_storage_columnname($field->id(), $column_name);
     $current['fields'][$real_name] = $attributes;
   }
 
   // Add indexes.
   foreach ($schema['indexes'] as $index_name => $columns) {
-    $real_name = _field_sql_storage_indexname($field['field_name'], $index_name);
+    $real_name = _field_sql_storage_indexname($field->id(), $index_name);
     foreach ($columns as $column_name) {
       // Indexes can be specified as either a column name or an array with
       // column name and length. Allow for either case.
       if (is_array($column_name)) {
         $current['indexes'][$real_name][] = array(
-          _field_sql_storage_columnname($field['field_name'], $column_name[0]),
+          _field_sql_storage_columnname($field->id(), $column_name[0]),
           $column_name[1],
         );
       }
       else {
-        $current['indexes'][$real_name][] = _field_sql_storage_columnname($field['field_name'], $column_name);
+        $current['indexes'][$real_name][] = _field_sql_storage_columnname($field->id(), $column_name);
       }
     }
   }
 
   // Add foreign keys.
   foreach ($schema['foreign keys'] as $specifier => $specification) {
-    $real_name = _field_sql_storage_indexname($field['field_name'], $specifier);
+    $real_name = _field_sql_storage_indexname($field->id(), $specifier);
     $current['foreign keys'][$real_name]['table'] = $specification['table'];
     foreach ($specification['columns'] as $column_name => $referenced) {
-      $sql_storage_column = _field_sql_storage_columnname($field['field_name'], $column_name);
+      $sql_storage_column = _field_sql_storage_columnname($field->id(), $column_name);
       $current['foreign keys'][$real_name]['columns'][$sql_storage_column] = $referenced;
     }
   }
 
   // Construct the revision table.
   $revision = $current;
-  $revision['description'] = "Revision archive storage for {$deleted}field {$field['id']} ({$field['field_name']})";
+  $revision['description'] = "Revision archive storage for {$deleted}field {$field->id()} ({$field->id()})";
   $revision['primary key'] = array('entity_type', 'entity_id', 'revision_id', 'deleted', 'delta', 'langcode');
   $revision['fields']['revision_id']['not null'] = TRUE;
   $revision['fields']['revision_id']['description'] = 'The entity revision id this data is attached to';
@@ -255,7 +255,7 @@ function field_sql_storage_field_storage_create_field($field) {
  */
 function field_sql_storage_field_create_field($field) {
   // Rebuild the schema now that the field has been saved.
-  if ($field['storage']['type'] == 'field_sql_storage') {
+  if ($field->storage['type'] == 'field_sql_storage') {
     drupal_get_schema(NULL, TRUE);
   }
 }
@@ -267,7 +267,7 @@ function field_sql_storage_field_create_field($field) {
  * data.
  */
 function field_sql_storage_field_update_forbid($field, $prior_field) {
-  if ($field->hasData() && $field['columns'] != $prior_field['columns']) {
+  if ($field->hasData() && $field->getSchema('columns') != $prior_field->getSchema('columns')) {
     throw new FieldUpdateForbiddenException("field_sql_storage cannot change the schema for an existing field with data.");
   }
 }
@@ -323,7 +323,7 @@ function field_sql_storage_field_storage_update_field($field, $prior_field) {
 
     foreach ($prior_schema['indexes'] as $name => $columns) {
       if (!isset($schema['indexes'][$name]) || $columns != $schema['indexes'][$name]) {
-        $real_name = _field_sql_storage_indexname($field['field_name'], $name);
+        $real_name = _field_sql_storage_indexname($field->id(), $name);
         db_drop_index($table, $real_name);
         db_drop_index($revision_table, $real_name);
       }
@@ -332,19 +332,19 @@ function field_sql_storage_field_storage_update_field($field, $prior_field) {
     $revision_table = _field_sql_storage_revision_tablename($field);
     foreach ($schema['indexes'] as $name => $columns) {
       if (!isset($prior_schema['indexes'][$name]) || $columns != $prior_schema['indexes'][$name]) {
-        $real_name = _field_sql_storage_indexname($field['field_name'], $name);
+        $real_name = _field_sql_storage_indexname($field->id(), $name);
         $real_columns = array();
         foreach ($columns as $column_name) {
           // Indexes can be specified as either a column name or an array with
           // column name and length. Allow for either case.
           if (is_array($column_name)) {
             $real_columns[] = array(
-              _field_sql_storage_columnname($field['field_name'], $column_name[0]),
+              _field_sql_storage_columnname($field->id(), $column_name[0]),
               $column_name[1],
             );
           }
           else {
-            $real_columns[] = _field_sql_storage_columnname($field['field_name'], $column_name);
+            $real_columns[] = _field_sql_storage_columnname($field->id(), $column_name);
           }
         }
         db_add_index($table, $real_name, $real_columns);
@@ -360,7 +360,7 @@ function field_sql_storage_field_storage_update_field($field, $prior_field) {
  */
 function field_sql_storage_field_storage_delete_field($field) {
   // Mark all data associated with the field for deletion.
-  $field['deleted'] = FALSE;
+  $field->deleted = FALSE;
   $table = _field_sql_storage_tablename($field);
   $revision_table = _field_sql_storage_revision_tablename($field);
   db_update($table)
@@ -368,7 +368,7 @@ function field_sql_storage_field_storage_delete_field($field) {
     ->execute();
 
   // Move the table to a unique name while the table contents are being deleted.
-  $field['deleted'] = TRUE;
+  $field->deleted = TRUE;
   $new_table = _field_sql_storage_tablename($field);
   $revision_new_table = _field_sql_storage_revision_tablename($field);
   db_rename_table($table, $new_table);
@@ -388,7 +388,7 @@ function field_sql_storage_field_storage_load($entity_type, $entities, $age, $fi
     // on each field individually is more efficient than loading all fields in
     // memory upfront with field_info_field_by_ids().
     $field = field_info_field_by_id($field_id);
-    $field_name = $field['field_name'];
+    $field_name = $field->id();
     $table = $load_current ? _field_sql_storage_tablename($field) : _field_sql_storage_revision_tablename($field);
 
     $query = db_select($table, 't')
@@ -410,11 +410,11 @@ function field_sql_storage_field_storage_load($entity_type, $entities, $age, $fi
         $delta_count[$row->entity_id][$row->langcode] = 0;
       }
 
-      if ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED || $delta_count[$row->entity_id][$row->langcode] < $field['cardinality']) {
+      if ($field->cardinality == FIELD_CARDINALITY_UNLIMITED || $delta_count[$row->entity_id][$row->langcode] < $field->cardinality) {
         $item = array();
         // For each column declared by the field, populate the item
         // from the prefixed database column.
-        foreach ($field['columns'] as $column => $attributes) {
+        foreach ($field->getSchema('columns') as $column => $attributes) {
           $column_name = _field_sql_storage_columnname($field_name, $column);
           $item[$column] = $row->$column_name;
         }
@@ -441,7 +441,7 @@ function field_sql_storage_field_storage_write(EntityInterface $entity, $op, $fi
 
   foreach ($fields as $field_id) {
     $field = field_info_field_by_id($field_id);
-    $field_name = $field['field_name'];
+    $field_name = $field->id();
     $table_name = _field_sql_storage_tablename($field);
     $revision_name = _field_sql_storage_revision_tablename($field);
 
@@ -475,7 +475,7 @@ function field_sql_storage_field_storage_write(EntityInterface $entity, $op, $fi
     // Prepare the multi-insert query.
     $do_insert = FALSE;
     $columns = array('entity_type', 'entity_id', 'revision_id', 'bundle', 'delta', 'langcode');
-    foreach ($field['columns'] as $column => $attributes) {
+    foreach ($field->getSchema('columns') as $column => $attributes) {
       $columns[] = _field_sql_storage_columnname($field_name, $column);
     }
     $query = db_insert($table_name)->fields($columns);
@@ -495,7 +495,7 @@ function field_sql_storage_field_storage_write(EntityInterface $entity, $op, $fi
           'delta' => $delta,
           'langcode' => $langcode,
         );
-        foreach ($field['columns'] as $column => $attributes) {
+        foreach ($field->getSchema('columns') as $column => $attributes) {
           $record[_field_sql_storage_columnname($field_name, $column)] = isset($item[$column]) ? $item[$column] : NULL;
         }
         $query->values($record);
@@ -503,7 +503,7 @@ function field_sql_storage_field_storage_write(EntityInterface $entity, $op, $fi
           $revision_query->values($record);
         }
 
-        if ($field['cardinality'] != FIELD_CARDINALITY_UNLIMITED && ++$delta_count == $field['cardinality']) {
+        if ($field->cardinality != FIELD_CARDINALITY_UNLIMITED && ++$delta_count == $field->cardinality) {
           break;
         }
       }
@@ -528,8 +528,8 @@ function field_sql_storage_field_storage_write(EntityInterface $entity, $op, $fi
  */
 function field_sql_storage_field_storage_delete(EntityInterface $entity, $fields) {
   foreach (field_info_instances($entity->entityType(), $entity->bundle()) as $instance) {
-    if (isset($fields[$instance['field_id']])) {
-      $field = field_info_field_by_id($instance['field_id']);
+    if (isset($fields[$instance->field_uuid])) {
+      $field = field_info_field_by_id($instance->field_uuid);
       field_sql_storage_field_storage_purge($entity, $field, $instance);
     }
   }
@@ -580,18 +580,18 @@ function field_sql_storage_field_storage_delete_revision(EntityInterface $entity
  * This function simply marks for deletion all data associated with the field.
  */
 function field_sql_storage_field_storage_delete_instance($instance) {
-  $field = field_info_field($instance['field_name']);
+  $field = field_info_field($instance->getFieldName());
   $table_name = _field_sql_storage_tablename($field);
   $revision_name = _field_sql_storage_revision_tablename($field);
   db_update($table_name)
     ->fields(array('deleted' => 1))
-    ->condition('entity_type', $instance['entity_type'])
-    ->condition('bundle', $instance['bundle'])
+    ->condition('entity_type', $instance->entity_type)
+    ->condition('bundle', $instance->bundle)
     ->execute();
   db_update($revision_name)
     ->fields(array('deleted' => 1))
-    ->condition('entity_type', $instance['entity_type'])
-    ->condition('bundle', $instance['bundle'])
+    ->condition('entity_type', $instance->entity_type)
+    ->condition('bundle', $instance->bundle)
     ->execute();
 }
 
@@ -602,8 +602,8 @@ function field_sql_storage_entity_bundle_rename($entity_type, $bundle_old, $bund
   // We need to account for deleted or inactive fields and instances.
   $instances = field_read_instances(array('entity_type' => $entity_type, 'bundle' => $bundle_new), array('include_deleted' => TRUE, 'include_inactive' => TRUE));
   foreach ($instances as $instance) {
-    $field = field_info_field_by_id($instance['field_id']);
-    if ($field['storage']['type'] == 'field_sql_storage') {
+    $field = field_info_field_by_id($instance->field_uuid);
+    if ($field->storage['type'] == 'field_sql_storage') {
       $table_name = _field_sql_storage_tablename($field);
       $revision_name = _field_sql_storage_revision_tablename($field);
       db_update($table_name)
@@ -638,10 +638,11 @@ function field_sql_storage_field_storage_purge_field($field) {
  */
 function field_sql_storage_field_storage_details($field) {
   $details = array();
-  if (!empty($field['columns'])) {
+  $columns = $field->getSchema('columns');
+  if (!empty($columns)) {
      // Add field columns.
-    foreach ($field['columns'] as $column_name => $attributes) {
-      $real_name = _field_sql_storage_columnname($field['field_name'], $column_name);
+    foreach ($columns as $column_name => $attributes) {
+      $real_name = _field_sql_storage_columnname($field->id(), $column_name);
       $columns[$column_name] = $real_name;
     }
     return array(
diff --git a/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Entity/Tables.php b/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Entity/Tables.php
index 11aebc0..ac930f0 100644
--- a/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Entity/Tables.php
+++ b/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Entity/Tables.php
@@ -119,7 +119,8 @@ function addField($field, $type, $langcode) {
         if ($key < $count) {
           $next = $specifiers[$key + 1];
           // Is this a field column?
-          if (isset($field['columns'][$next]) || in_array($next, Field::getReservedColumns())) {
+          $schema = $field->getSchema('columns');
+          if (isset($schema[$next]) || in_array($next, Field::getReservedColumns())) {
             // Use it.
             $column = $next;
             // Do not process it again.
@@ -137,7 +138,7 @@ function addField($field, $type, $langcode) {
 
             // Get the field definitions form a mocked entity.
             $entity = entity_create($entity_type, array());
-            $propertyDefinitions = $entity->{$field['field_name']}->getPropertyDefinitions();
+            $propertyDefinitions = $entity->{$field->id()}->getPropertyDefinitions();
 
             // If the column is not yet known, ie. the
             // $node->field_image->entity case then use the id source as the
@@ -157,7 +158,7 @@ function addField($field, $type, $langcode) {
           $column = 'value';
         }
         $table = $this->ensureFieldTable($index_prefix, $field, $type, $langcode, $base_table, $entity_id_field, $field_id_field);
-        $sql_column = _field_sql_storage_columnname($field['field_name'], $column);
+        $sql_column = _field_sql_storage_columnname($field->id(), $column);
       }
       // This is an entity property (non-configurable field).
       else {
@@ -240,10 +241,10 @@ protected function ensureEntityTable($index_prefix, $property, $type, $langcode,
    * @throws \Drupal\Core\Entity\Query\QueryException
    */
   protected function ensureFieldTable($index_prefix, &$field, $type, $langcode, $base_table, $entity_id_field, $field_id_field) {
-    $field_name = $field['field_name'];
+    $field_name = $field->id();
     if (!isset($this->fieldTables[$index_prefix . $field_name])) {
       $table = $this->sqlQuery->getMetaData('age') == FIELD_LOAD_CURRENT ? _field_sql_storage_tablename($field) : _field_sql_storage_revision_tablename($field);
-      if ($field['cardinality'] != 1) {
+      if ($field->cardinality != 1) {
         $this->sqlQuery->addMetaData('simple_query', FALSE);
       }
       $entity_type = $this->sqlQuery->getMetaData('entity_type');
diff --git a/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Tests/FieldSqlStorageTest.php b/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Tests/FieldSqlStorageTest.php
index 00ebd9c..2d5ed5f 100644
--- a/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Tests/FieldSqlStorageTest.php
+++ b/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Tests/FieldSqlStorageTest.php
@@ -101,7 +101,7 @@ function testFieldAttachLoad() {
     for ($evid = 0; $evid < 4; ++$evid) {
       $values[$evid] = array();
       // Note: we insert one extra value ('<=' instead of '<').
-      for ($delta = 0; $delta <= $this->field['cardinality']; $delta++) {
+      for ($delta = 0; $delta <= $this->field->cardinality; $delta++) {
         $value = mt_rand(1, 127);
         $values[$evid][] = $value;
         $query->values(array($entity_type, $eid, $evid, $delta, $langcode, $value));
@@ -117,10 +117,10 @@ function testFieldAttachLoad() {
     $query->execute();
 
     // Load the "most current revision"
-    $entity = field_test_create_entity($eid, 0, $this->instance['bundle']);
+    $entity = field_test_create_entity($eid, 0, $this->instance->bundle);
     field_attach_load($entity_type, array($eid => $entity));
     foreach ($values[0] as $delta => $value) {
-      if ($delta < $this->field['cardinality']) {
+      if ($delta < $this->field->cardinality) {
         $this->assertEqual($entity->{$this->field_name}[$langcode][$delta]['value'], $value, "Value $delta is loaded correctly for current revision");
       }
       else {
@@ -130,10 +130,10 @@ function testFieldAttachLoad() {
 
     // Load every revision
     for ($evid = 0; $evid < 4; ++$evid) {
-      $entity = field_test_create_entity($eid, $evid, $this->instance['bundle']);
+      $entity = field_test_create_entity($eid, $evid, $this->instance->bundle);
       field_attach_load_revision($entity_type, array($eid => $entity));
       foreach ($values[$evid] as $delta => $value) {
-        if ($delta < $this->field['cardinality']) {
+        if ($delta < $this->field->cardinality) {
           $this->assertEqual($entity->{$this->field_name}[$langcode][$delta]['value'], $value, "Value $delta for revision $evid is loaded correctly");
         }
         else {
@@ -146,7 +146,7 @@ function testFieldAttachLoad() {
     // loaded.
     $eid = $evid = 1;
     $unavailable_langcode = 'xx';
-    $entity = field_test_create_entity($eid, $evid, $this->instance['bundle']);
+    $entity = field_test_create_entity($eid, $evid, $this->instance->bundle);
     $values = array($entity_type, $eid, $evid, 0, $unavailable_langcode, mt_rand(1, 127));
     db_insert($this->table)->fields($columns)->values($values)->execute();
     db_insert($this->revision_table)->fields($columns)->values($values)->execute();
@@ -160,14 +160,14 @@ function testFieldAttachLoad() {
    */
   function testFieldAttachInsertAndUpdate() {
     $entity_type = 'test_entity';
-    $entity = field_test_create_entity(0, 0, $this->instance['bundle']);
+    $entity = field_test_create_entity(0, 0, $this->instance->bundle);
     $langcode = Language::LANGCODE_NOT_SPECIFIED;
 
     // Test insert.
     $values = array();
     // Note: we try to insert one extra value ('<=' instead of '<').
     // TODO : test empty values filtering and "compression" (store consecutive deltas).
-    for ($delta = 0; $delta <= $this->field['cardinality']; $delta++) {
+    for ($delta = 0; $delta <= $this->field->cardinality; $delta++) {
       $values[$delta]['value'] = mt_rand(1, 127);
     }
     $entity->{$this->field_name}[$langcode] = $rev_values[0] = $values;
@@ -175,7 +175,7 @@ function testFieldAttachInsertAndUpdate() {
 
     $rows = db_select($this->table, 't')->fields('t')->execute()->fetchAllAssoc('delta', PDO::FETCH_ASSOC);
     foreach ($values as $delta => $value) {
-      if ($delta < $this->field['cardinality']) {
+      if ($delta < $this->field->cardinality) {
         $this->assertEqual($rows[$delta][$this->field_name . '_value'], $value['value'], t("Value $delta is inserted correctly"));
       }
       else {
@@ -187,14 +187,14 @@ function testFieldAttachInsertAndUpdate() {
     $entity = field_test_create_entity(0, 1, $this->instance->bundle);
     $values = array();
     // Note: we try to update one extra value ('<=' instead of '<').
-    for ($delta = 0; $delta <= $this->field['cardinality']; $delta++) {
+    for ($delta = 0; $delta <= $this->field->cardinality; $delta++) {
       $values[$delta]['value'] = mt_rand(1, 127);
     }
     $entity->{$this->field_name}[$langcode] = $rev_values[1] = $values;
     field_attach_update($entity);
     $rows = db_select($this->table, 't')->fields('t')->execute()->fetchAllAssoc('delta', PDO::FETCH_ASSOC);
     foreach ($values as $delta => $value) {
-      if ($delta < $this->field['cardinality']) {
+      if ($delta < $this->field->cardinality) {
         $this->assertEqual($rows[$delta][$this->field_name . '_value'], $value['value'], t("Value $delta is updated correctly"));
       }
       else {
@@ -510,7 +510,7 @@ function testFieldSqlStorageForeignKeys() {
     $schema = $schemas[_field_sql_storage_tablename($field)];
     $this->assertEqual(count($schema['foreign keys']), 1, 'There is 1 foreign key in the schema');
     $foreign_key = reset($schema['foreign keys']);
-    $foreign_key_column = _field_sql_storage_columnname($field['field_name'], $foreign_key_name);
+    $foreign_key_column = _field_sql_storage_columnname($field->id(), $foreign_key_name);
     $this->assertEqual($foreign_key['table'], $foreign_key_name, 'Foreign key table name preserved in the schema');
     $this->assertEqual($foreign_key['columns'][$foreign_key_column], 'id', 'Foreign key column name preserved in the schema');
   }
diff --git a/core/modules/field_ui/field_ui.admin.inc b/core/modules/field_ui/field_ui.admin.inc
index 4f429cc..e8c7776 100644
--- a/core/modules/field_ui/field_ui.admin.inc
+++ b/core/modules/field_ui/field_ui.admin.inc
@@ -31,10 +31,10 @@ function field_ui_fields_list() {
 
         // Initialize the row if we encounter the field for the first time.
         if (!isset($rows[$field_name])) {
-          $rows[$field_name]['class'] = $field['locked'] ? array('menu-disabled') : array('');
-          $rows[$field_name]['data'][0] = $field['locked'] ? t('@field_name (Locked)', array('@field_name' => $field_name)) : $field_name;
-          $module_name = $field_types[$field['type']]['module'];
-          $rows[$field_name]['data'][1] = $field_types[$field['type']]['label'] . ' ' . t('(module: !module)', array('!module' => $modules[$module_name]->info['name']));
+          $rows[$field_name]['class'] = $field->locked ? array('menu-disabled') : array('');
+          $rows[$field_name]['data'][0] = $field->locked ? t('@field_name (Locked)', array('@field_name' => $field_name)) : $field_name;
+          $module_name = $field_types[$field->type]['module'];
+          $rows[$field_name]['data'][1] = $field_types[$field->type]['label'] . ' ' . t('(module: !module)', array('!module' => $modules[$module_name]->info['name']));
         }
 
         // Add the current instance.
diff --git a/core/modules/field_ui/field_ui.api.php b/core/modules/field_ui/field_ui.api.php
index b3bf03e..24a77ae 100644
--- a/core/modules/field_ui/field_ui.api.php
+++ b/core/modules/field_ui/field_ui.api.php
@@ -34,7 +34,7 @@
  *   The form definition for the field settings.
  */
 function hook_field_settings_form($field, $instance) {
-  $settings = $field['settings'];
+  $settings = $field->settings;
   $form['max_length'] = array(
     '#type' => 'number',
     '#title' => t('Maximum length'),
@@ -63,7 +63,7 @@ function hook_field_settings_form($field, $instance) {
  *   The form definition for the field instance settings.
  */
 function hook_field_instance_settings_form($field, $instance, $form_state) {
-  $settings = $instance['settings'];
+  $settings = $instance->settings;
 
   $form['text_processing'] = array(
     '#type' => 'radios',
@@ -74,7 +74,7 @@ function hook_field_instance_settings_form($field, $instance, $form_state) {
       t('Filtered text (user selects text format)'),
     ),
   );
-  if ($field['type'] == 'text_with_summary') {
+  if ($field->type == 'text_with_summary') {
     $form['display_summary'] = array(
       '#type' => 'select',
       '#title' => t('Display summary'),
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverview.php b/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverview.php
index bb09eab..9084189 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverview.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverview.php
@@ -145,14 +145,14 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL,
         '#region_callback' => array($this, 'getRowRegion'),
         '#js_settings' => array(
           'rowHandler' => 'field',
-          'defaultFormatter' => $field_types[$field['type']]['default_formatter'],
+          'defaultFormatter' => $field_types[$field->type]['default_formatter'],
         ),
         'human_name' => array(
-          '#markup' => check_plain($instance['label']),
+          '#markup' => check_plain($instance->label()),
         ),
         'weight' => array(
           '#type' => 'textfield',
-          '#title' => t('Weight for @title', array('@title' => $instance['label'])),
+          '#title' => t('Weight for @title', array('@title' => $instance->label())),
           '#title_display' => 'invisible',
           '#default_value' => $display_options ? $display_options['weight'] : '0',
           '#size' => 3,
@@ -161,7 +161,7 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL,
         'parent_wrapper' => array(
           'parent' => array(
             '#type' => 'select',
-            '#title' => t('Label display for @title', array('@title' => $instance['label'])),
+            '#title' => t('Label display for @title', array('@title' => $instance->label())),
             '#title_display' => 'invisible',
             '#options' => $table['#parent_options'],
             '#empty_value' => '',
@@ -176,19 +176,19 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL,
         ),
         'label' => array(
           '#type' => 'select',
-          '#title' => t('Label display for @title', array('@title' => $instance['label'])),
+          '#title' => t('Label display for @title', array('@title' => $instance->label())),
           '#title_display' => 'invisible',
           '#options' => $field_label_options,
           '#default_value' => $display_options ? $display_options['label'] : 'above',
         ),
       );
 
-      $formatter_options = $this->formatterManager->getOptions($field['type']);
+      $formatter_options = $this->formatterManager->getOptions($field->type);
       $formatter_options['hidden'] = '<' . t('Hidden') . '>';
       $table[$name]['format'] = array(
         'type' => array(
           '#type' => 'select',
-          '#title' => t('Formatter for @title', array('@title' => $instance['label'])),
+          '#title' => t('Formatter for @title', array('@title' => $instance->label())),
           '#title_display' => 'invisible',
           '#options' => $formatter_options,
           '#default_value' => $display_options ? $display_options['type'] : 'hidden',
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php b/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php
index ec602ff..4bd89d0 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php
@@ -126,19 +126,19 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL,
 
     // Fields.
     foreach ($instances as $name => $instance) {
-      $field = field_info_field($instance['field_name']);
-      $widget_configuration = $entity_form_display->getComponent($instance['field_name']);
+      $field = field_info_field($instance->getFieldName());
+      $widget_configuration = $entity_form_display->getComponent($instance->getFieldName());
       $admin_field_path = $this->adminPath . '/fields/' . $instance->id();
       $table[$name] = array(
         '#attributes' => array('class' => array('draggable', 'tabledrag-leaf')),
         '#row_type' => 'field',
         '#region_callback' => array($this, 'getRowRegion'),
         'label' => array(
-          '#markup' => check_plain($instance['label']),
+          '#markup' => check_plain($instance->label()),
         ),
         'weight' => array(
           '#type' => 'textfield',
-          '#title' => t('Weight for @title', array('@title' => $instance['label'])),
+          '#title' => t('Weight for @title', array('@title' => $instance->label())),
           '#title_display' => 'invisible',
           '#default_value' => $widget_configuration ? $widget_configuration['weight'] : '0',
           '#size' => 3,
@@ -147,7 +147,7 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL,
         'parent_wrapper' => array(
           'parent' => array(
             '#type' => 'select',
-            '#title' => t('Parent for @title', array('@title' => $instance['label'])),
+            '#title' => t('Parent for @title', array('@title' => $instance->label())),
             '#title_display' => 'invisible',
             '#options' => $table['#parent_options'],
             '#empty_value' => '',
@@ -161,11 +161,11 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL,
           ),
         ),
         'field_name' => array(
-          '#markup' => $instance['field_name'],
+          '#markup' => $instance->getFieldName(),
         ),
         'type' => array(
           '#type' => 'link',
-          '#title' => $field_types[$field['type']]['label'],
+          '#title' => $field_types[$field->type]['label'],
           '#href' => $admin_field_path . '/field',
           '#options' => array('attributes' => array('title' => t('Edit field settings.'))),
         ),
@@ -193,7 +193,7 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL,
         '#links' => $links,
       );
 
-      if (!empty($field['locked'])) {
+      if (!empty($field->locked)) {
         $table[$name]['operations'] = array('#markup' => t('Locked'));
         $table[$name]['#attributes']['class'][] = 'menu-disabled';
       }
@@ -505,7 +505,7 @@ protected function validateAddNew(array $form, array &$form_state) {
       }
       // Field name validation.
       else {
-        $field_name = $field['field_name'];
+        $field_name = $field->id();
 
         // Add the field prefix.
         $field_name = config('field_ui.settings')->get('field_prefix') . $field_name;
@@ -565,8 +565,8 @@ protected function validateAddExisting(array $form, array &$form_state) {
           form_set_error('fields][_add_existing_field][widget_type', t('Re-use existing field: you need to select a widget.'));
         }
         // Wrong widget type.
-        elseif ($field['field_name'] && ($existing_field = field_info_field($field['field_name']))) {
-          $widget_types = $this->widgetManager->getOptions($existing_field['type']);
+        elseif ($field->id() && ($existing_field = field_info_field($field->id()))) {
+          $widget_types = $this->widgetManager->getOptions($existing_field->type);
           if (!isset($widget_types[$field['widget_type']])) {
             form_set_error('fields][_add_existing_field][widget_type', t('Re-use existing field: invalid widget.'));
           }
@@ -612,7 +612,7 @@ public function submitForm(array &$form, array &$form_state) {
         'translatable' => $values['translatable'],
       );
       $instance = array(
-        'field_name' => $field['field_name'],
+        'field_name' => $field->id(),
         'entity_type' => $this->entity_type,
         'bundle' => $this->bundle,
         'label' => $values['label'],
@@ -627,7 +627,7 @@ public function submitForm(array &$form, array &$form_state) {
         // Make sure the field is displayed in the 'default' form mode (using
         // the configured widget and default settings).
         entity_get_form_display($this->entity_type, $this->bundle, 'default')
-          ->setComponent($field['field_name'], array(
+          ->setComponent($field->id(), array(
             'type' => $values['widget_type'],
             'weight' => $values['weight'],
           ))
@@ -637,7 +637,7 @@ public function submitForm(array &$form, array &$form_state) {
         // default formatter and settings). It stays hidden for other view
         // modes until it is explicitly configured.
         entity_get_display($this->entity_type, $this->bundle, 'default')
-          ->setComponent($field['field_name'])
+          ->setComponent($field->id())
           ->save();
 
         // Always show the field settings step, as the cardinality needs to be
@@ -646,10 +646,10 @@ public function submitForm(array &$form, array &$form_state) {
         $destinations[] = $this->adminPath . '/fields/' . $new_instance->id();
 
         // Store new field information for any additional submit handlers.
-        $form_state['fields_added']['_add_new_field'] = $field['field_name'];
+        $form_state['fields_added']['_add_new_field'] = $field->id();
       }
       catch (\Exception $e) {
-        drupal_set_message(t('There was a problem creating field %label: !message', array('%label' => $instance['label'], '!message' => $e->getMessage())), 'error');
+        drupal_set_message(t('There was a problem creating field %label: !message', array('%label' => $instance->label(), '!message' => $e->getMessage())), 'error');
       }
     }
 
@@ -657,12 +657,12 @@ public function submitForm(array &$form, array &$form_state) {
     if (!empty($form_values['_add_existing_field']['field_name'])) {
       $values = $form_values['_add_existing_field'];
       $field = field_info_field($values['field_name']);
-      if (!empty($field['locked'])) {
+      if (!empty($field->locked)) {
         drupal_set_message(t('The field %label cannot be added because it is locked.', array('%label' => $values['label'])), 'error');
       }
       else {
         $instance = array(
-          'field_name' => $field['field_name'],
+          'field_name' => $field->id(),
           'entity_type' => $this->entity_type,
           'bundle' => $this->bundle,
           'label' => $values['label'],
@@ -675,7 +675,7 @@ public function submitForm(array &$form, array &$form_state) {
           // Make sure the field is displayed in the 'default' form mode (using
           // the configured widget and default settings).
           entity_get_form_display($this->entity_type, $this->bundle, 'default')
-            ->setComponent($field['field_name'], array(
+            ->setComponent($field->id(), array(
               'type' => $values['widget_type'],
               'weight' => $values['weight'],
             ))
@@ -685,15 +685,15 @@ public function submitForm(array &$form, array &$form_state) {
           // default formatter and settings). It stays hidden for other view
           // modes until it is explicitly configured.
           entity_get_display($this->entity_type, $this->bundle, 'default')
-            ->setComponent($field['field_name'])
+            ->setComponent($field->id())
             ->save();
 
           $destinations[] = $this->adminPath . '/fields/' . $new_instance->id();
           // Store new field information for any additional submit handlers.
-          $form_state['fields_added']['_add_existing_field'] = $instance['field_name'];
+          $form_state['fields_added']['_add_existing_field'] = $instance->getFieldName();
         }
         catch (\Exception $e) {
-          drupal_set_message(t('There was a problem creating field instance %label: @message.', array('%label' => $instance['label'], '@message' => $e->getMessage())), 'error');
+          drupal_set_message(t('There was a problem creating field instance %label: @message.', array('%label' => $instance->label(), '@message' => $e->getMessage())), 'error');
         }
       }
     }
@@ -748,23 +748,23 @@ protected function getExistingFieldOptions() {
         // No need to look in the current bundle.
         if (!($existing_bundle == $this->bundle && $existing_entity_type == $this->entity_type)) {
           foreach ($instances as $instance) {
-            $field = field_info_field($instance['field_name']);
+            $field = field_info_field($instance->getFieldName());
             // Don't show
             // - locked fields,
             // - fields already in the current bundle,
             // - fields that cannot be added to the entity type,
             // - fields that should not be added via user interface.
 
-            if (empty($field['locked'])
-              && !field_info_instance($this->entity_type, $field['field_name'], $this->bundle)
-              && (empty($field['entity_types']) || in_array($this->entity_type, $field['entity_types']))
-              && empty($field_types[$field['type']]['no_ui'])) {
-              $widget = entity_get_form_display($instance['entity_type'], $instance['bundle'], 'default')->getComponent($instance['field_name']);
-              $info[$instance['field_name']] = array(
-                'type' => $field['type'],
-                'type_label' => $field_types[$field['type']]['label'],
-                'field' => $field['field_name'],
-                'label' => $instance['label'],
+            if (empty($field->locked)
+              && !field_info_instance($this->entity_type, $field->id(), $this->bundle)
+              && (empty($field->entity_types) || in_array($this->entity_type, $field->entity_types))
+              && empty($field_types[$field->type]['no_ui'])) {
+              $widget = entity_get_form_display($instance->entity_type, $instance->bundle, 'default')->getComponent($instance->getFieldName());
+              $info[$instance->getFieldName()] = array(
+                'type' => $field->type,
+                'type_label' => $field_types[$field->type]['label'],
+                'field' => $field->id(),
+                'label' => $instance->label(),
                 'widget_type' => $widget['type'],
               );
             }
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldEditForm.php b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldEditForm.php
index c2f0a45..32163d1 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldEditForm.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldEditForm.php
@@ -87,7 +87,7 @@ public function buildForm(array $form, array &$form_state, FieldInstanceInterfac
     }
 
     // Build the configurable field values.
-    $cardinality = $field['cardinality'];
+    $cardinality = $field->cardinality;
     $form['field']['cardinality_container'] = array(
       // We can't use the container element because it doesn't support the title
       // or description properties.
@@ -123,10 +123,10 @@ public function buildForm(array $form, array &$form_state, FieldInstanceInterfac
     );
 
     // Build the non-configurable field values.
-    $form['field']['field_name'] = array('#type' => 'value', '#value' => $field['field_name']);
-    $form['field']['type'] = array('#type' => 'value', '#value' => $field['type']);
-    $form['field']['module'] = array('#type' => 'value', '#value' => $field['module']);
-    $form['field']['active'] = array('#type' => 'value', '#value' => $field['active']);
+    $form['field']['field_name'] = array('#type' => 'value', '#value' => $field->id());
+    $form['field']['type'] = array('#type' => 'value', '#value' => $field->type);
+    $form['field']['module'] = array('#type' => 'value', '#value' => $field->module);
+    $form['field']['active'] = array('#type' => 'value', '#value' => $field->active);
 
     // Add settings provided by the field module. The field module is
     // responsible for not returning settings that cannot be changed if
@@ -134,7 +134,7 @@ public function buildForm(array $form, array &$form_state, FieldInstanceInterfac
     $form['field']['settings'] = array(
       '#weight' => 10,
     );
-    $additions = \Drupal::moduleHandler()->invoke($field['module'], 'field_settings_form', array($field, $this->instance));
+    $additions = \Drupal::moduleHandler()->invoke($field->module, 'field_settings_form', array($field, $this->instance));
     if (is_array($additions)) {
       $form['field']['settings'] += $additions;
     }
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldInstanceEditForm.php b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldInstanceEditForm.php
index 393997a..f380de2 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldInstanceEditForm.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldInstanceEditForm.php
@@ -28,8 +28,8 @@ public function getFormID() {
   public function buildForm(array $form, array &$form_state, FieldInstanceInterface $field_instance = NULL) {
     parent::buildForm($form, $form_state, $field_instance);
 
-    $bundle = $this->instance['bundle'];
-    $entity_type = $this->instance['entity_type'];
+    $bundle = $this->instance->bundle;
+    $entity_type = $this->instance->entity_type;
     $field = $this->instance->getField();
     $entity_form_display = entity_get_form_display($entity_type, $bundle, 'default');
     $bundles = entity_get_bundles();
@@ -42,11 +42,11 @@ public function buildForm(array $form, array &$form_state, FieldInstanceInterfac
     $form['#field'] = $field;
     $form['#entity_form_display'] = $entity_form_display;
     // Create an arbitrary entity object (used by the 'default value' widget).
-    $ids = (object) array('entity_type' => $this->instance['entity_type'], 'bundle' => $this->instance['bundle'], 'entity_id' => NULL);
+    $ids = (object) array('entity_type' => $this->instance->entity_type, 'bundle' => $this->instance->bundle, 'entity_id' => NULL);
     $form['#entity'] = _field_create_entity_from_ids($ids);
     $form['#entity']->field_ui_default_value = TRUE;
 
-    if (!empty($field['locked'])) {
+    if (!empty($field->locked)) {
       $form['locked'] = array(
         '#markup' => t('The field %field is locked and cannot be edited.', array('%field' => $this->instance->label())),
       );
@@ -61,7 +61,7 @@ public function buildForm(array $form, array &$form_state, FieldInstanceInterfac
     // Build the non-configurable instance values.
     $form['instance']['field_name'] = array(
       '#type' => 'value',
-      '#value' => $this->instance['field_name'],
+      '#value' => $this->instance->getFieldName(),
     );
     $form['instance']['entity_type'] = array(
       '#type' => 'value',
@@ -76,7 +76,7 @@ public function buildForm(array $form, array &$form_state, FieldInstanceInterfac
     $form['instance']['label'] = array(
       '#type' => 'textfield',
       '#title' => t('Label'),
-      '#default_value' => $this->instance->label() ?: $field['field_name'],
+      '#default_value' => $this->instance->label() ?: $field->id(),
       '#required' => TRUE,
       '#weight' => -20,
     );
@@ -84,7 +84,7 @@ public function buildForm(array $form, array &$form_state, FieldInstanceInterfac
     $form['instance']['description'] = array(
       '#type' => 'textarea',
       '#title' => t('Help text'),
-      '#default_value' => !empty($this->instance['description']) ? $this->instance['description'] : '',
+      '#default_value' => !empty($this->instance->description) ? $this->instance->description : '',
       '#rows' => 5,
       '#description' => t('Instructions to present to the user below this field on the editing form.<br />Allowed HTML tags: @tags', array('@tags' => _field_filter_xss_display_allowed_tags())) . '<br />' . t('This field supports tokens.'),
       '#weight' => -10,
@@ -93,12 +93,12 @@ public function buildForm(array $form, array &$form_state, FieldInstanceInterfac
     $form['instance']['required'] = array(
       '#type' => 'checkbox',
       '#title' => t('Required field'),
-      '#default_value' => !empty($this->instance['required']),
+      '#default_value' => !empty($this->instance->required),
       '#weight' => -5,
     );
 
     // Add additional field instance settings from the field module.
-    $additions = \Drupal::moduleHandler()->invoke($field['module'], 'field_instance_settings_form', array($field, $this->instance, $form_state));
+    $additions = \Drupal::moduleHandler()->invoke($field->module, 'field_instance_settings_form', array($field, $this->instance, $form_state));
     if (is_array($additions)) {
       $form['instance']['settings'] = $additions;
       $form['instance']['settings']['#weight'] = 10;
@@ -110,7 +110,7 @@ public function buildForm(array $form, array &$form_state, FieldInstanceInterfac
     $form['instance']['widget']['#weight'] = 20;
 
     // Add handling for default value if not provided by any other module.
-    if (field_behaviors_widget('default_value', $this->instance) == FIELD_BEHAVIOR_DEFAULT && empty($this->instance['default_value_function'])) {
+    if (field_behaviors_widget('default_value', $this->instance) == FIELD_BEHAVIOR_DEFAULT && empty($this->instance->default_value_function)) {
       $form['instance']['default_value_widget'] = $this->getDefaultValueWidget($field, $form, $form_state);
     }
 
@@ -133,7 +133,7 @@ public function buildForm(array $form, array &$form_state, FieldInstanceInterfac
   public function validateForm(array &$form, array &$form_state) {
     // Take the incoming values as the $this->instance definition, so that the 'default
     // value' gets validated using the instance settings being submitted.
-    $field_name = $this->instance['field_name'];
+    $field_name = $this->instance->getFieldName();
     $entity = $form['#entity'];
     $entity_form_display = $form['#entity_form_display'];
     $field = $this->instance->getField();
@@ -150,7 +150,7 @@ public function validateForm(array &$form, array &$form_state) {
 
       // Validate the value.
       $errors = array();
-      $function = $field['module'] . '_field_validate';
+      $function = $field->module . '_field_validate';
       if (function_exists($function)) {
         $function(NULL, $field, $this->instance, Language::LANGCODE_NOT_SPECIFIED, $items, $errors);
       }
@@ -182,7 +182,7 @@ public function submitForm(array &$form, array &$form_state) {
       $items = array();
       $entity_form_display->getWidget($this->instance->getField()->id)->extractFormValues($entity, Language::LANGCODE_NOT_SPECIFIED, $items, $element, $form_state);
 
-      $this->instance['default_value'] = $items ? $items : NULL;
+      $this->instance->default_value = $items ? $items : NULL;
     }
 
     // Handle widget settings.
@@ -199,8 +199,8 @@ public function submitForm(array &$form, array &$form_state) {
 
     drupal_set_message(t('Saved %label configuration.', array('%label' => $this->instance->label())));
 
-    if ($this->instance['required'] && empty($this->instance['default_value']) && empty($this->instance['default_value_function']) && $this->instance['widget']['type'] == 'field_hidden') {
-      drupal_set_message(t('Field %label is required and uses the "hidden" widget. You might want to configure a default value.', array('%label' => $this->instance['label'])), 'warning');
+    if ($this->instance['required'] && empty($this->instance->default_value) && empty($this->instance->default_value_function) && $this->instance['widget']['type'] == 'field_hidden') {
+      drupal_set_message(t('Field %label is required and uses the "hidden" widget. You might want to configure a default value.', array('%label' => $this->instance->label())), 'warning');
     }
 
     $form_state['redirect'] = $this->getNextDestination();
@@ -215,7 +215,7 @@ public function delete(array &$form, array &$form_state) {
       $destination = drupal_get_destination();
       unset($_GET['destination']);
     }
-    $form_state['redirect'] = array('admin/structure/types/manage/' . $this->instance['bundle'] . '/fields/' . $this->instance->id() . '/delete', array('query' => $destination));
+    $form_state['redirect'] = array('admin/structure/types/manage/' . $this->instance->bundle . '/fields/' . $this->instance->id() . '/delete', array('query' => $destination));
   }
 
   /**
@@ -238,12 +238,12 @@ protected function getDefaultValueWidget($field, array &$form, &$form_state) {
 
     // Adjust the instance definition used for the form element. We want a
     // non-required input and no description.
-    $this->instance['required'] = FALSE;
-    $this->instance['description'] = '';
+    $this->instance->required = FALSE;
+    $this->instance->description = '';
 
     // Adjust the instance definition to use the default widget of this field type
     // instead of the hidden widget.
-    if ($this->instance['widget']['type'] == 'field_hidden') {
+    /*if ($this->instance['widget']['type'] == 'field_hidden') {
       $field_type = field_info_field_types($field['type']);
       $default_widget = $this->widgetManager->getDefinition($field_type['default_widget']);
 
@@ -252,15 +252,15 @@ protected function getDefaultValueWidget($field, array &$form, &$form_state) {
         'settings' => $default_widget['settings'],
         'weight' => 0,
       );
-    }
+    }*/
 
     // Insert the widget. Since we do not use the "official" instance definition,
     // the whole flow cannot use field_invoke_method().
     $items = array();
-    if (!empty($this->instance['default_value'])) {
-      $items = (array) $this->instance['default_value'];
+    if (!empty($this->instance->default_value)) {
+      $items = (array) $this->instance->default_value;
     }
-    $element += $entity_form_display->getWidget($this->instance->getField()->id)->form($entity, Language::LANGCODE_NOT_SPECIFIED, $items, $element, $form_state);
+    $element += $entity_form_display->getWidget($this->instance->getFieldName())->form($entity, Language::LANGCODE_NOT_SPECIFIED, $items, $element, $form_state);
 
     return $element;
   }
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldWidgetTypeForm.php b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldWidgetTypeForm.php
index 4f44947..f257c56 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldWidgetTypeForm.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldWidgetTypeForm.php
@@ -27,11 +27,11 @@ public function getFormID() {
   public function buildForm(array $form, array &$form_state, FieldInstanceInterface $field_instance = NULL) {
     parent::buildForm($form, $form_state, $field_instance);
 
-    drupal_set_title($this->instance['label']);
+    drupal_set_title($this->instance->label());
 
-    $bundle = $this->instance['bundle'];
-    $entity_type = $this->instance['entity_type'];
-    $field_name = $this->instance['field_name'];
+    $bundle = $this->instance->bundle;
+    $entity_type = $this->instance->entity_type;
+    $field_name = $this->instance->getFieldName();
 
     $entity_form_display = entity_get_form_display($entity_type, $bundle, 'default');
     $field = $this->instance->getField();
@@ -49,7 +49,7 @@ public function buildForm(array $form, array &$form_state, FieldInstanceInterfac
       '#type' => 'select',
       '#title' => t('Widget type'),
       '#required' => TRUE,
-      '#options' => $this->widgetManager->getOptions($field['type']),
+      '#options' => $this->widgetManager->getOptions($field->type),
       '#default_value' => $entity_form_display->getWidget($field_name)->getPluginId(),
       '#description' => t('The type of form element you would like to present to the user when creating this field in the %type type.', array('%type' => $bundle_label)),
     );
@@ -83,14 +83,14 @@ public function submitForm(array &$form, array &$form_state) {
 
     try {
       $entity_form_display->save();
-      drupal_set_message(t('Changed the widget for field %label.', array('%label' => $instance['label'])));
+      drupal_set_message(t('Changed the widget for field %label.', array('%label' => $instance->label())));
 
-      if ($instance['required'] && empty($instance['default_value']) && empty($instance['default_value_function']) && $instance['widget']['type'] == 'field_hidden') {
-        drupal_set_message(t('Field %label is required and uses the "hidden" widget. You might want to configure a default value.', array('%label' => $instance['label'])), 'warning');
-      }
+      /*if ($instance->required && empty($instance->default_value) && empty($instance->default_value_function) && $instance['widget']['type'] == 'field_hidden') {
+        drupal_set_message(t('Field %label is required and uses the "hidden" widget. You might want to configure a default value.', array('%label' => $instance->label())), 'warning');
+      }*/
     }
     catch (\Exception $e) {
-      drupal_set_message(t('There was a problem changing the widget for field %label.', array('%label' => $instance['label'])), 'error');
+      drupal_set_message(t('There was a problem changing the widget for field %label.', array('%label' => $instance->label())), 'error');
     }
 
     $form_state['redirect'] = $this->getNextDestination();
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageDisplayTest.php b/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageDisplayTest.php
index c643cd0..d31fbb6 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageDisplayTest.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageDisplayTest.php
@@ -178,10 +178,6 @@ function testNonInitializedFields() {
     );
     $this->fieldUIAddNewField('admin/structure/types/manage/' . $this->type, $edit);
 
-    // Check that no settings have been set for the 'teaser' mode.
-    $instance = field_info_instance('node', 'field_test', $this->type);
-    $this->assertFalse(isset($instance['display']['teaser']));
-
     // Check that the field appears as 'hidden' on the 'Manage display' page
     // for the 'teaser' mode.
     $this->drupalGet('admin/structure/types/manage/' . $this->type . '/display/teaser');
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageFieldsTest.php b/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageFieldsTest.php
index 471a575..a5fc564 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageFieldsTest.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageFieldsTest.php
@@ -233,11 +233,11 @@ function assertFieldSettings($bundle, $field_name, $string = 'dummy test string'
     field_info_cache_clear();
     // Assert field settings.
     $field = field_info_field($field_name);
-    $this->assertTrue($field['settings']['test_field_setting'] == $string, 'Field settings were found.');
+    $this->assertTrue($field->settings['test_field_setting'] == $string, 'Field settings were found.');
 
     // Assert instance and widget settings.
     $instance = field_info_instance($entity_type, $field_name, $bundle);
-    $this->assertTrue($instance['settings']['test_instance_setting'] == $string, 'Field instance settings were found.');
+    $this->assertTrue($instance->settings['test_instance_setting'] == $string, 'Field instance settings were found.');
 
     // Assert widget settings.
     $widget_configuration = entity_get_form_display($entity_type, $bundle, 'default')->getComponent($field_name);
@@ -313,7 +313,7 @@ function testDefaultValue() {
     $this->assertText("Saved $field_name configuration", 'The form was successfully submitted.');
     field_info_cache_clear();
     $instance = field_info_instance('node', $field_name, $this->type);
-    $this->assertEqual($instance['default_value'], array(array('value' => 1)), 'The default value was correctly saved.');
+    $this->assertEqual($instance->default_value, array(array('value' => 1)), 'The default value was correctly saved.');
 
     // Check that the default value shows up in the form
     $this->drupalGet($admin_path);
@@ -325,10 +325,10 @@ function testDefaultValue() {
     $this->assertText("Saved $field_name configuration", 'The form was successfully submitted.');
     field_info_cache_clear();
     $instance = field_info_instance('node', $field_name, $this->type);
-    $this->assertEqual($instance['default_value'], NULL, 'The default value was correctly saved.');
+    $this->assertEqual($instance->default_value, NULL, 'The default value was correctly saved.');
 
     // Change the widget to TestFieldWidgetNoDefault.
-    entity_get_form_display($instance['entity_type'], $instance['bundle'], 'default')
+    entity_get_form_display($instance->entity_type, $instance->bundle, 'default')
       ->setComponent($field_name, array(
         'type' => 'test_field_widget_no_default',
       ))
@@ -431,13 +431,13 @@ function testHiddenFields() {
     // Create a field and an instance programmatically.
     $field_name = 'hidden_test_field';
     entity_create('field_entity', array('field_name' => $field_name, 'type' => $field_name))->save();
-    $instance = array(
+    $instance = entity_create('field_instance', array(
       'field_name' => $field_name,
       'bundle' => $this->type,
       'entity_type' => 'node',
       'label' => t('Hidden field'),
-    );
-    entity_create('field_instance', $instance)->save();
+    ));
+    $instance->save();
     entity_get_form_display('node', $this->type, 'default')
       ->setComponent($field_name)
       ->save();
@@ -446,7 +446,7 @@ function testHiddenFields() {
     // Check that the newly added instance appears on the 'Manage Fields'
     // screen.
     $this->drupalGet($bundle_path);
-    $this->assertFieldByXPath('//table[@id="field-overview"]//td[1]', $instance['label'], 'Field was created and appears in the overview page.');
+    $this->assertFieldByXPath('//table[@id="field-overview"]//td[1]', $instance->label, 'Field was created and appears in the overview page.');
 
     // Check that the instance does not appear in the 're-use existing field' row
     // on other bundles.
diff --git a/core/modules/file/file.field.inc b/core/modules/file/file.field.inc
index a46696c..1745168 100644
--- a/core/modules/file/file.field.inc
+++ b/core/modules/file/file.field.inc
@@ -38,8 +38,8 @@ function file_field_info() {
  * Implements hook_field_settings_form().
  */
 function file_field_settings_form($field, $instance) {
-  $defaults = field_info_field_settings($field['type']);
-  $settings = array_merge($defaults, $field['settings']);
+  $defaults = field_info_field_settings($field->type);
+  $settings = array_merge($defaults, $field->settings);
 
   $form['#attached']['library'][] = array('file', 'drupal.file');
 
@@ -81,7 +81,7 @@ function file_field_settings_form($field, $instance) {
  * Implements hook_field_instance_settings_form().
  */
 function file_field_instance_settings_form($field, $instance) {
-  $settings = $instance['settings'];
+  $settings = $instance->settings;
 
   $form['file_directory'] = array(
     '#type' => 'textfield',
@@ -246,8 +246,8 @@ function file_field_update(EntityInterface $entity, $field, $instance, $langcode
   // Compare the original field values with the ones that are being saved.
   $original = $entity->original->getBCEntity();
   $original_fids = array();
-  if (!empty($original->{$field['field_name']}[$langcode])) {
-    foreach ($original->{$field['field_name']}[$langcode] as $original_item) {
+  if (!empty($original->{$field->id()}[$langcode])) {
+    foreach ($original->{$field->id()}[$langcode] as $original_item) {
       $original_fids[] = $original_item['fid'];
       if (isset($original_item['fid']) && !in_array($original_item['fid'], $current_fids)) {
         // Decrement the file usage count by 1.
@@ -303,7 +303,7 @@ function file_field_is_empty($item, $field_type) {
  *   Boolean TRUE if the file will be displayed, FALSE if the file is hidden.
  */
 function file_field_displayed($item, $field) {
-  if (!empty($field['settings']['display_field'])) {
+  if (!empty($field->settings['display_field'])) {
     return (bool) $item['display'];
   }
   return TRUE;
@@ -405,8 +405,8 @@ function file_field_widget_multiple_count_validate($element, &$form_state, $form
   $field = field_info_field($element['#field_name']);
   $uploaded = count($values['fids']);
   $count = $uploaded + $current;
-  if ($count > $field['cardinality']) {
-    $keep = $uploaded - $count + $field['cardinality'];
+  if ($count > $field->cardinality) {
+    $keep = $uploaded - $count + $field->cardinality;
     $removed_files = array_slice($values['fids'], $keep);
     $removed_names = array();
     foreach ($removed_files as $fid) {
@@ -417,8 +417,8 @@ function file_field_widget_multiple_count_validate($element, &$form_state, $form
       t(
         'Field %field can only hold @max values but there were @count uploaded. The following files have been omitted as a result: %list.',
         array(
-          '%field' => $field['field_name'],
-          '@max' => $field['cardinality'],
+          '%field' => $field->id(),
+          '@max' => $field->cardinality,
           '@count' => $keep,
           '%list' => implode(', ', $removed_names),
         )
@@ -824,7 +824,7 @@ function theme_file_upload_help($variables) {
  *   fid, FALSE if it doesn't.
  */
 function file_field_find_file_reference_column($field) {
-  foreach ($field['foreign keys'] as $data) {
+  foreach ($field->getSchema('foreign keys') as $data) {
     if ($data['table'] == 'file_managed') {
       foreach ($data['columns'] as $field_column => $column) {
         if ($column == 'fid') {
diff --git a/core/modules/file/file.module b/core/modules/file/file.module
index 87b263e..82b04c2 100644
--- a/core/modules/file/file.module
+++ b/core/modules/file/file.module
@@ -1591,12 +1591,12 @@ function file_get_file_references(File $file, $field = NULL, $age = FIELD_LOAD_R
             $current_field = field_info_field($field_name);
             // If this is the first time this field type is seen, check
             // whether it references files.
-            if (!isset($field_columns[$current_field['type']])) {
-              $field_columns[$current_field['type']] = file_field_find_file_reference_column($current_field);
+            if (!isset($field_columns[$current_field->type])) {
+              $field_columns[$current_field->type] = file_field_find_file_reference_column($current_field);
             }
             // If the field type does reference files then record it.
-            if ($field_columns[$current_field['type']]) {
-              $file_fields[$entity_type][$bundle][$field_name] = $field_columns[$current_field['type']];
+            if ($field_columns[$current_field->type]) {
+              $file_fields[$entity_type][$bundle][$field_name] = $field_columns[$current_field->type];
             }
           }
         }
@@ -1627,7 +1627,7 @@ function file_get_file_references(File $file, $field = NULL, $age = FIELD_LOAD_R
   if ($field || $field_type) {
     foreach ($return as $field_name => $data) {
       $current_field = field_info_field($field_name);
-      if (($field_type && $current_field['type'] != $field_type) || ($field && $field['id'] != $current_field['id'])) {
+      if (($field_type && $current_field->type != $field_type) || ($field && $field->id() != $current_field->id)) {
         unset($return[$field_name]);
       }
     }
diff --git a/core/modules/file/file.views.inc b/core/modules/file/file.views.inc
index c9e271f..1ea90d5 100644
--- a/core/modules/file/file.views.inc
+++ b/core/modules/file/file.views.inc
@@ -455,12 +455,12 @@ function file_field_views_data($field) {
   $data = field_views_field_default_views_data($field);
   foreach ($data as $table_name => $table_data) {
     // Add the relationship only on the fid field.
-    $data[$table_name][$field['field_name'] . '_fid']['relationship'] = array(
+    $data[$table_name][$field->id() . '_fid']['relationship'] = array(
       'id' => 'standard',
       'base' => 'file_managed',
       'entity type' => 'file',
       'base field' => 'fid',
-      'label' => t('file from !field_name', array('!field_name' => $field['field_name'])),
+      'label' => t('file from !field_name', array('!field_name' => $field->id())),
     );
   }
 
@@ -473,11 +473,11 @@ function file_field_views_data($field) {
  * Views integration to provide reverse relationships on file fields.
  */
 function file_field_views_data_views_data_alter(&$data, $field) {
-  foreach ($field['bundles'] as $entity_type => $bundles) {
+  foreach ($field->getBundles() as $entity_type => $bundles) {
     $entity_info = entity_get_info($entity_type);
-    $pseudo_field_name = 'reverse_' . $field['field_name'] . '_' . $entity_type;
+    $pseudo_field_name = 'reverse_' . $field->id() . '_' . $entity_type;
 
-    list($label, $all_labels) = field_views_field_label($field['field_name']);
+    list($label, $all_labels) = field_views_field_label($field->id());
     $entity = $entity_info['label'];
     if ($entity == t('Node')) {
       $entity = t('Content');
@@ -487,12 +487,12 @@ function file_field_views_data_views_data_alter(&$data, $field) {
       'title' => t('@entity using @field', array('@entity' => $entity, '@field' => $label)),
       'help' => t('Relate each @entity with a @field set to the file.', array('@entity' => $entity, '@field' => $label)),
       'id' => 'entity_reverse',
-      'field_name' => $field['field_name'],
+      'field_name' => $field->id(),
       'field table' => _field_sql_storage_tablename($field),
-      'field field' => $field['field_name'] . '_fid',
+      'field field' => $field->id() . '_fid',
       'base' => $entity_info['base_table'],
       'base field' => $entity_info['entity_keys']['id'],
-      'label' => t('!field_name', array('!field_name' => $field['field_name'])),
+      'label' => t('!field_name', array('!field_name' => $field->id())),
       'join_extra' => array(
         0 => array(
           'field' => 'entity_type',
diff --git a/core/modules/file/lib/Drupal/file/Tests/FileFieldTestBase.php b/core/modules/file/lib/Drupal/file/Tests/FileFieldTestBase.php
index e501573..ab4e2c7 100644
--- a/core/modules/file/lib/Drupal/file/Tests/FileFieldTestBase.php
+++ b/core/modules/file/lib/Drupal/file/Tests/FileFieldTestBase.php
@@ -98,7 +98,7 @@ function createFileField($name, $type_name, $field_settings = array(), $instance
    *   A list of widget settings that will be added to the widget defaults.
    */
   function attachFileField($name, $entity_type, $bundle, $instance_settings = array(), $widget_settings = array()) {
-    $instance = array(
+    $instance_definition = array(
       'field_name' => $name,
       'label' => $name,
       'entity_type' => $entity_type,
@@ -106,8 +106,8 @@ function attachFileField($name, $entity_type, $bundle, $instance_settings = arra
       'required' => !empty($instance_settings['required']),
       'settings' => array(),
     );
-    $instance['settings'] = array_merge($instance['settings'], $instance_settings);
-    entity_create('field_instance', $instance)->save();
+    $instance_definition['settings'] = array_merge($instance['settings'], $instance_settings);
+    entity_create('field_instance', $instance_definition)->save();
 
     entity_get_form_display($entity_type, $bundle, 'default')
       ->setComponent($name, array(
@@ -122,12 +122,12 @@ function attachFileField($name, $entity_type, $bundle, $instance_settings = arra
    */
   function updateFileField($name, $type_name, $instance_settings = array(), $widget_settings = array()) {
     $instance = field_info_instance('node', $name, $type_name);
-    $instance['settings'] = array_merge($instance['settings'], $instance_settings);
+    $instance->settings = array_merge($instance->settings, $instance_settings);
 
     $instance->save();
 
-    entity_get_form_display($instance['entity_type'], $instance['bundle'], 'default')
-      ->setComponent($instance['field_name'], array(
+    entity_get_form_display($instance->entity_type, $instance->bundle, 'default')
+      ->setComponent($instance->getFieldName(), array(
         'settings' => $widget_settings,
       ))
       ->save();
@@ -161,7 +161,7 @@ function uploadNodeFile($file, $field_name, $nid_or_type, $new_revision = TRUE,
     // Attach a file to the node.
     $field = field_info_field($field_name);
     $name = 'files[' . $field_name . '_' . $langcode . '_0]';
-    if ($field['cardinality'] != 1) {
+    if ($field->cardinality != 1) {
       $name .= '[]';
     }
     $edit[$name] = drupal_realpath($file->getFileUri());
diff --git a/core/modules/file/lib/Drupal/file/Tests/FileFieldValidateTest.php b/core/modules/file/lib/Drupal/file/Tests/FileFieldValidateTest.php
index 174ba99..7537d0a 100644
--- a/core/modules/file/lib/Drupal/file/Tests/FileFieldValidateTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/FileFieldValidateTest.php
@@ -39,7 +39,7 @@ function testRequired() {
     $langcode = Language::LANGCODE_NOT_SPECIFIED;
     $edit = array("title" => $this->randomName());
     $this->drupalPost('node/add/' . $type_name, $edit, t('Save and publish'));
-    $this->assertRaw(t('!title field is required.', array('!title' => $instance['label'])), t('Node save failed when required file field was empty.'));
+    $this->assertRaw(t('!title field is required.', array('!title' => $instance->label())), t('Node save failed when required file field was empty.'));
 
     // Create a new node with the uploaded file.
     $nid = $this->uploadNodeFile($test_file, $field_name, $type_name);
@@ -58,7 +58,7 @@ function testRequired() {
     // Try to post a new node without uploading a file in the multivalue field.
     $edit = array('title' => $this->randomName());
     $this->drupalPost('node/add/' . $type_name, $edit, t('Save and publish'));
-    $this->assertRaw(t('!title field is required.', array('!title' => $instance['label'])), t('Node save failed when required multiple value file field was empty.'));
+    $this->assertRaw(t('!title field is required.', array('!title' => $instance->label())), t('Node save failed when required multiple value file field was empty.'));
 
     // Create a new node with the uploaded file into the multivalue field.
     $nid = $this->uploadNodeFile($test_file, $field_name, $type_name);
diff --git a/core/modules/file/tests/file_module_test.module b/core/modules/file/tests/file_module_test.module
index 19096f9..d0c4757 100644
--- a/core/modules/file/tests/file_module_test.module
+++ b/core/modules/file/tests/file_module_test.module
@@ -88,7 +88,7 @@ function file_module_test_form_submit($form, &$form_state) {
  * Implements hook_file_download_access().
  */
 function file_module_test_file_download_access($field, EntityInterface $entity, File $file) {
-  $instance = field_info_instance($entity->entityType(), $field['field_name'], $entity->bundle());
+  $instance = field_info_instance($entity->entityType(), $field->id(), $entity->bundle());
   // Allow the file to be downloaded only if the given arguments are correct.
   // If any are wrong, $instance will be NULL.
   if (empty($instance)) {
diff --git a/core/modules/forum/forum.module b/core/modules/forum/forum.module
index 36fffda..ab97854 100644
--- a/core/modules/forum/forum.module
+++ b/core/modules/forum/forum.module
@@ -174,7 +174,7 @@ function forum_menu_local_tasks(&$data, $router_item, $root_path) {
       $links = array();
       // Loop through all bundles for forum taxonomy vocabulary field.
       $field = field_info_field('taxonomy_forums');
-      foreach ($field['bundles']['node'] as $type) {
+      foreach ($field->getBundles('node') as $type) {
         if (node_access('create', $type)) {
           $links[$type] = array(
             '#theme' => 'menu_local_action',
diff --git a/core/modules/image/image.admin.inc b/core/modules/image/image.admin.inc
index 935df53..59cc1c6 100644
--- a/core/modules/image/image.admin.inc
+++ b/core/modules/image/image.admin.inc
@@ -5,8 +5,6 @@
  * Administration pages for image settings.
  */
 
-use Symfony\Component\HttpFoundation\RedirectResponse;
-
 /**
  * Menu callback; Listing of all current image styles.
  */
@@ -286,7 +284,7 @@ function image_effect_form($form, &$form_state, $style, $effect) {
   // If there's no configuration for this image effect, return to
   // the image style page.
   if (!isset($effect['form callback'])) {
-    return new RedirectResponse(url('admin/config/media/image-styles/manage/' . $style->id(), array('absolute' => TRUE)));
+    drupal_goto('admin/config/media/image-styles/manage/' . $style->id());
   }
   $form_state['image_style'] = $style;
   $form_state['image_effect'] = $effect;
diff --git a/core/modules/image/image.field.inc b/core/modules/image/image.field.inc
index ab64ffe..78a180e 100644
--- a/core/modules/image/image.field.inc
+++ b/core/modules/image/image.field.inc
@@ -57,8 +57,8 @@ function image_field_info() {
  * Implements hook_field_settings_form().
  */
 function image_field_settings_form($field, $instance) {
-  $defaults = field_info_field_settings($field['type']);
-  $settings = array_merge($defaults, $field['settings']);
+  $defaults = field_info_field_settings($field->type);
+  $settings = array_merge($defaults, $field->settings);
 
   $scheme_options = array();
   foreach (file_get_stream_wrappers(STREAM_WRAPPERS_WRITE_VISIBLE) as $scheme => $stream_wrapper) {
@@ -79,7 +79,7 @@ function image_field_settings_form($field, $instance) {
     '#title' => t('Default image'),
     '#type' => 'managed_file',
     '#description' => t('If no image is uploaded, this image will be shown on display.'),
-    '#default_value' => empty($field['settings']['default_image']) ? array() : array($field['settings']['default_image']),
+    '#default_value' => empty($field->settings['default_image']) ? array() : array($field->settings['default_image']),
     '#upload_location' => $settings['uri_scheme'] . '://default_images/',
   );
 
@@ -90,7 +90,7 @@ function image_field_settings_form($field, $instance) {
  * Implements hook_field_instance_settings_form().
  */
 function image_field_instance_settings_form($field, $instance) {
-  $settings = $instance['settings'];
+  $settings = $instance->settings;
 
   // Use the file field instance settings form as a basis.
   $form = file_field_instance_settings_form($field, $instance);
@@ -198,7 +198,7 @@ function image_field_instance_settings_form($field, $instance) {
     '#type' => 'managed_file',
     '#description' => t("If no image is uploaded, this image will be shown on display and will override the field's default image."),
     '#default_value' => empty($settings['default_image']) ? array() : array($settings['default_image']),
-    '#upload_location' => $field['settings']['uri_scheme'] . '://default_images/',
+    '#upload_location' => $field->settings['uri_scheme'] . '://default_images/',
   );
 
   return $form;
@@ -233,12 +233,12 @@ function image_field_prepare_view($entity_type, $entities, $field, $instances, $
     if (empty($items[$id])) {
       $fid = array();
       // Use the default for the instance if one is available.
-      if (!empty($instances[$id]['settings']['default_image'])) {
-        $fid = array($instances[$id]['settings']['default_image']);
+      if (!empty($instances[$id]->settings['default_image'])) {
+        $fid = array($instances[$id]->settings['default_image']);
       }
       // Otherwise, use the default for the field.
-      elseif (!empty($field['settings']['default_image'])) {
-        $fid = array($field['settings']['default_image']);
+      elseif (!empty($field->settings['default_image'])) {
+        $fid = array($field->settings['default_image']);
       }
 
       // Add the default image if one is found.
diff --git a/core/modules/image/image.module b/core/modules/image/image.module
index bdcb5e9..1840744 100644
--- a/core/modules/image/image.module
+++ b/core/modules/image/image.module
@@ -350,14 +350,14 @@ function image_file_predelete(File $file) {
  * Implements hook_field_delete_field().
  */
 function image_field_delete_field($field) {
-  if ($field['type'] != 'image') {
+  if ($field->type != 'image') {
     return;
   }
 
   // The value of a managed_file element can be an array if #extended == TRUE.
-  $fid = (isset($field['settings']['default_image']['fids']) ? $field['settings']['default_image']['fids'] : $field['settings']['default_image']);
+  $fid = (isset($field->settings['default_image']['fids']) ? $field->settings['default_image']['fids'] : $field->settings['default_image']);
   if ($fid && ($file = file_load($fid[0]))) {
-    file_usage()->delete($file, 'image', 'default_image', $field['id']);
+    file_usage()->delete($file, 'image', 'default_image', $field->uuid);
   }
 }
 
@@ -370,8 +370,8 @@ function image_field_update_field($field, $prior_field) {
   }
 
   // The value of a managed_file element can be an array if #extended == TRUE.
-  $fid_new = (isset($field['settings']['default_image']['fids']) ? $field['settings']['default_image']['fids'] : $field['settings']['default_image']);
-  $fid_old = (isset($prior_field['settings']['default_image']['fids']) ? $prior_field['settings']['default_image']['fids'] : $prior_field['settings']['default_image']);
+  $fid_new = (isset($field->settings['default_image']['fids']) ? $field->settings['default_image']['fids'] : $field->settings['default_image']);
+  $fid_old = (isset($prior_field->settings['default_image']['fids']) ? $prior_field->settings['default_image']['fids'] : $prior_field->settings['default_image']);
 
   $file_new = $fid_new ? file_load($fid_new) : FALSE;
 
@@ -381,18 +381,18 @@ function image_field_update_field($field, $prior_field) {
     if ($file_new) {
       $file_new->status = FILE_STATUS_PERMANENT;
       $file_new->save();
-      file_usage()->add($file_new, 'image', 'default_image', $field['uuid']);
+      file_usage()->add($file_new, 'image', 'default_image', $field->uuid);
     }
 
     // Is there an old file?
     if ($fid_old && ($file_old = file_load($fid_old[0]))) {
-      file_usage()->delete($file_old, 'image', 'default_image', $field['uuid']);
+      file_usage()->delete($file_old, 'image', 'default_image', $field->uuid);
     }
   }
 
   // If the upload destination changed, then move the file.
-  if ($file_new && (file_uri_scheme($file_new->getFileUri()) != $field['settings']['uri_scheme'])) {
-    $directory = $field['settings']['uri_scheme'] . '://default_images/';
+  if ($file_new && (file_uri_scheme($file_new->getFileUri()) != $field->settings['uri_scheme'])) {
+    $directory = $field->settings['uri_scheme'] . '://default_images/';
     file_prepare_directory($directory, FILE_CREATE_DIRECTORY);
     file_move($file_new, $directory . $file_new->filename);
   }
@@ -403,21 +403,21 @@ function image_field_update_field($field, $prior_field) {
  */
 function image_field_delete_instance($instance) {
   // Only act on image fields.
-  $field = field_read_field($instance['field_name']);
-  if ($field['type'] != 'image') {
+  $field = field_read_field($instance->getFieldName());
+  if ($field->type != 'image') {
     return;
   }
 
   // The value of a managed_file element can be an array if the #extended
   // property is set to TRUE.
-  $fid = $instance['settings']['default_image'];
+  $fid = $instance->settings['default_image'];
   if (is_array($fid)) {
     $fid = $fid['fid'];
   }
 
   // Remove the default image when the instance is deleted.
   if ($fid && ($file = file_load($fid))) {
-    file_usage()->delete($file, 'image', 'default_image', $instance['id']);
+    file_usage()->delete($file, 'image', 'default_image', $instance->uuid);
   }
 }
 
@@ -426,18 +426,18 @@ function image_field_delete_instance($instance) {
  */
 function image_field_update_instance($instance, $prior_instance) {
   // Only act on image fields.
-  $field = field_read_field($instance['field_name']);
-  if ($field['type'] != 'image') {
+  $field = field_read_field($instance->getFieldName());
+  if ($field->type != 'image') {
     return;
   }
 
   // The value of a managed_file element can be an array if the #extended
   // property is set to TRUE.
-  $fid_new = $instance['settings']['default_image'];
+  $fid_new = $instance->settings['default_image'];
   if (isset($fid_new['fids'])) {
     $fid_new = $fid_new['fids'];
   }
-  $fid_old = $prior_instance['settings']['default_image'];
+  $fid_old = $prior_instance->settings['default_image'];
   if (isset($fid_old['fids'])) {
     $fid_old = $fid_old['fids'];
   }
@@ -449,17 +449,17 @@ function image_field_update_instance($instance, $prior_instance) {
     if ($file_new) {
       $file_new->status = FILE_STATUS_PERMANENT;
       $file_new->save();
-      file_usage()->add($file_new, 'image', 'default_image', $instance['uuid']);
+      file_usage()->add($file_new, 'image', 'default_image', $instance->uuid);
     }
     // Delete the old file, if present.
     if ($fid_old && ($file_old = file_load($fid_old[0]))) {
-      file_usage()->delete($file_old, 'image', 'default_image', $instance['uuid']);
+      file_usage()->delete($file_old, 'image', 'default_image', $instance->uuid);
     }
   }
 
   // If the upload destination changed, then move the file.
-  if ($file_new && (file_uri_scheme($file_new->getFileUri()) != $field['settings']['uri_scheme'])) {
-    $directory = $field['settings']['uri_scheme'] . '://default_images/';
+  if ($file_new && (file_uri_scheme($file_new->getFileUri()) != $field->settings['uri_scheme'])) {
+    $directory = $field->settings['uri_scheme'] . '://default_images/';
     file_prepare_directory($directory, FILE_CREATE_DIRECTORY);
     file_move($file_new, $directory . $file_new->filename);
   }
diff --git a/core/modules/image/image.views.inc b/core/modules/image/image.views.inc
index 77c4ea3..6ad2094 100644
--- a/core/modules/image/image.views.inc
+++ b/core/modules/image/image.views.inc
@@ -19,11 +19,11 @@ function image_field_views_data($field) {
   $data = field_views_field_default_views_data($field);
   foreach ($data as $table_name => $table_data) {
     // Add the relationship only on the fid field.
-    $data[$table_name][$field['field_name'] . '_fid']['relationship'] = array(
+    $data[$table_name][$field->id() . '_fid']['relationship'] = array(
       'id' => 'standard',
       'base' => 'file_managed',
       'base field' => 'fid',
-      'label' => t('image from !field_name', array('!field_name' => $field['field_name'])),
+      'label' => t('image from !field_name', array('!field_name' => $field->id())),
     );
   }
 
@@ -36,11 +36,11 @@ function image_field_views_data($field) {
  * Views integration to provide reverse relationships on image fields.
  */
 function image_field_views_data_views_data_alter(&$data, $field) {
-  foreach ($field['bundles'] as $entity_type => $bundles) {
+  foreach ($field->getBundles() as $entity_type => $bundles) {
     $entity_info = entity_get_info($entity_type);
-    $pseudo_field_name = 'reverse_' . $field['field_name'] . '_' . $entity_type;
+    $pseudo_field_name = 'reverse_' . $field->id() . '_' . $entity_type;
 
-    list($label, $all_labels) = field_views_field_label($field['field_name']);
+    list($label, $all_labels) = field_views_field_label($field->id());
     $entity = $entity_info['label'];
     if ($entity == t('Node')) {
       $entity = t('Content');
@@ -50,12 +50,12 @@ function image_field_views_data_views_data_alter(&$data, $field) {
       'title' => t('@entity using @field', array('@entity' => $entity, '@field' => $label)),
       'help' => t('Relate each @entity with a @field set to the image.', array('@entity' => $entity, '@field' => $label)),
       'id' => 'entity_reverse',
-      'field_name' => $field['field_name'],
+      'field_name' => $field->id(),
       'field table' => _field_sql_storage_tablename($field),
-      'field field' => $field['field_name'] . '_fid',
+      'field field' => $field->id() . '_fid',
       'base' => $entity_info['base_table'],
       'base field' => $entity_info['entity_keys']['id'],
-      'label' => t('!field_name', array('!field_name' => $field['field_name'])),
+      'label' => t('!field_name', array('!field_name' => $field->id())),
       'join_extra' => array(
         0 => array(
           'field' => 'entity_type',
diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageFieldDefaultImagesTest.php b/core/modules/image/lib/Drupal/image/Tests/ImageFieldDefaultImagesTest.php
index 164cbad..4cace67 100644
--- a/core/modules/image/lib/Drupal/image/Tests/ImageFieldDefaultImagesTest.php
+++ b/core/modules/image/lib/Drupal/image/Tests/ImageFieldDefaultImagesTest.php
@@ -62,12 +62,12 @@ function testDefaultImages() {
       'label' => $instance->label(),
       'required' => $instance->required,
       'settings' => array(
-        'default_image' => $default_images['instance2']->id(),
+        'default_image' => $default_images['instance2']->uuid,
       ),
     ));
     $instance2->save();
 
-    $widget_settings = entity_get_form_display($instance['entity_type'], $instance['bundle'], 'default')->getComponent($field['field_name']);
+    $widget_settings = entity_get_form_display($instance->entity_type, $instance->bundle, 'default')->getComponent($field->id());
     entity_get_form_display('node', 'page', 'default')
       ->setComponent($field->id(), $widget_settings)
       ->save();
@@ -142,7 +142,7 @@ function testDefaultImages() {
     );
 
     // Upload a new default for the field.
-    $field['settings']['default_image'] = array($default_images['field_new']->id());
+    $field->settings['default_image'] = array($default_images['field_new']->id());
     $field->save();
 
     // Confirm that the new default is used on the article field settings form.
@@ -177,7 +177,7 @@ function testDefaultImages() {
     );
 
     // Upload a new default for the article's field instance.
-    $instance['settings']['default_image'] = $default_images['instance_new']->id();
+    $instance->settings['default_image'] = $default_images['instance_new']->id();
     $instance->save();
 
     // Confirm the new field instance default is used on the article field
@@ -216,7 +216,7 @@ function testDefaultImages() {
     );
 
     // Remove the instance default from articles.
-    $instance['settings']['default_image'] = 0;
+    $instance->settings['default_image'] = 0;
     $instance->save();
 
     // Confirm the article field instance default has been removed.
diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageFieldDisplayTest.php b/core/modules/image/lib/Drupal/image/Tests/ImageFieldDisplayTest.php
index ccc39bd..fa3593d 100644
--- a/core/modules/image/lib/Drupal/image/Tests/ImageFieldDisplayTest.php
+++ b/core/modules/image/lib/Drupal/image/Tests/ImageFieldDisplayTest.php
@@ -232,7 +232,7 @@ function testImageFieldDefaultImage() {
     // Clear field info cache so the new default image is detected.
     field_info_cache_clear();
     $field = field_info_field($field_name);
-    $image = file_load($field['settings']['default_image']);
+    $image = file_load($field->settings['default_image']);
     $this->assertTrue($image->isPermanent(), 'The default image status is permanent.');
     $default_output = theme('image', array('uri' => $image->getFileUri()));
     $this->drupalGet('node/' . $node->nid);
@@ -260,7 +260,7 @@ function testImageFieldDefaultImage() {
     // Clear field info cache so the new default image is detected.
     field_info_cache_clear();
     $field = field_info_field($field_name);
-    $this->assertFalse($field['settings']['default_image'], 'Default image removed from field.');
+    $this->assertFalse($field->settings['default_image'], 'Default image removed from field.');
     // Create an image field that uses the private:// scheme and test that the
     // default image works as expected.
     $private_field_name = strtolower($this->randomName());
@@ -274,7 +274,7 @@ function testImageFieldDefaultImage() {
     field_info_cache_clear();
 
     $private_field = field_info_field($private_field_name);
-    $image = file_load($private_field['settings']['default_image']);
+    $image = file_load($private_field->settings['default_image']);
     $this->assertEqual('private', file_uri_scheme($image->getFileUri()), 'Default image uses private:// scheme.');
     $this->assertTrue($image->isPermanent(), 'The default image status is permanent.');
     // Create a new node with no image attached and ensure that default private
diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageFieldTestBase.php b/core/modules/image/lib/Drupal/image/Tests/ImageFieldTestBase.php
index 3b9be9f..e717e6b 100644
--- a/core/modules/image/lib/Drupal/image/Tests/ImageFieldTestBase.php
+++ b/core/modules/image/lib/Drupal/image/Tests/ImageFieldTestBase.php
@@ -69,17 +69,19 @@ function setUp() {
    *   A list of widget settings that will be added to the widget defaults.
    */
   function createImageField($name, $type_name, $field_settings = array(), $instance_settings = array(), $widget_settings = array()) {
-    $field = array(
+    $field_definition = array(
       'field_name' => $name,
       'type' => 'image',
       'settings' => array(),
       'cardinality' => !empty($field_settings['cardinality']) ? $field_settings['cardinality'] : 1,
     );
-    $field['settings'] = array_merge($field['settings'], $field_settings);
-    entity_create('field_entity', $field)->save();
+    $field_definition['settings'] = array_merge($field_definition['settings'], $field_settings);
+
+    $field = entity_create('field_entity', $field_definition);
+    $field->save();
 
     $instance = array(
-      'field_name' => $field['field_name'],
+      'field_name' => $field->id(),
       'entity_type' => 'node',
       'label' => $name,
       'bundle' => $type_name,
@@ -87,19 +89,19 @@ function createImageField($name, $type_name, $field_settings = array(), $instanc
       'description' => !empty($instance_settings['description']) ? $instance_settings['description'] : '',
       'settings' => array(),
     );
-    $instance['settings'] = array_merge($instance['settings'], $instance_settings);
+    $instance->settings = array_merge($instance->settings, $instance_settings);
     $field_instance = entity_create('field_instance', $instance);
     $field_instance->save();
 
     entity_get_form_display('node', $type_name, 'default')
-      ->setComponent($field['field_name'], array(
+      ->setComponent($field->id(), array(
         'type' => 'image_image',
         'settings' => $widget_settings,
       ))
       ->save();
 
     entity_get_display('node', $type_name, 'default')
-      ->setComponent($field['field_name'])
+      ->setComponent($field->id())
       ->save();
 
     return $field_instance;
diff --git a/core/modules/language/language.admin.inc b/core/modules/language/language.admin.inc
index ee3dbd1..e41f6bc 100644
--- a/core/modules/language/language.admin.inc
+++ b/core/modules/language/language.admin.inc
@@ -7,7 +7,6 @@
 
 use Drupal\Core\Language\Language;
 use Drupal\Core\Language\LanguageManager;
-use Symfony\Component\HttpFoundation\RedirectResponse;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 
 /**
@@ -299,7 +298,7 @@ function language_admin_delete_form($form, &$form_state, $language) {
 
   if (language_default()->langcode == $langcode) {
     drupal_set_message(t('The default language cannot be deleted.'));
-    return new RedirectResponse(url('admin/config/regional/language', array('absolute' => TRUE)));
+    drupal_goto('admin/config/regional/language');
   }
 
   // For other languages, warn the user that data loss is ahead.
diff --git a/core/modules/link/lib/Drupal/link/Tests/LinkFieldTest.php b/core/modules/link/lib/Drupal/link/Tests/LinkFieldTest.php
index b4033ff..0a5f9af 100644
--- a/core/modules/link/lib/Drupal/link/Tests/LinkFieldTest.php
+++ b/core/modules/link/lib/Drupal/link/Tests/LinkFieldTest.php
@@ -465,7 +465,7 @@ function testLinkSeparateFormatter() {
         // Update the field formatter settings.
         $display_options['settings'] = array($setting => $new_value);
         entity_get_display('entity_test', 'entity_test', 'full')
-          ->setComponent($this->field['field_name'], $display_options)
+          ->setComponent($this->field->id(), $display_options)
           ->save();
 
         $this->renderTestEntity($id);
diff --git a/core/modules/link/link.module b/core/modules/link/link.module
index bfd6ebf..1efbf17 100644
--- a/core/modules/link/link.module
+++ b/core/modules/link/link.module
@@ -44,7 +44,7 @@ function link_field_instance_settings_form($field, $instance) {
   $form['title'] = array(
     '#type' => 'radios',
     '#title' => t('Allow link text'),
-    '#default_value' => isset($instance['settings']['title']) ? $instance['settings']['title'] : DRUPAL_OPTIONAL,
+    '#default_value' => isset($instance->settings['title']) ? $instance->settings['title'] : DRUPAL_OPTIONAL,
     '#options' => array(
       DRUPAL_DISABLED => t('Disabled'),
       DRUPAL_OPTIONAL => t('Optional'),
diff --git a/core/modules/locale/locale.pages.inc b/core/modules/locale/locale.pages.inc
index 3400a3e..47ad131 100644
--- a/core/modules/locale/locale.pages.inc
+++ b/core/modules/locale/locale.pages.inc
@@ -8,7 +8,6 @@
 use Drupal\Core\Language\Language;
 use Drupal\locale\SourceString;
 use Drupal\locale\TranslationString;
-use Symfony\Component\HttpFoundation\RedirectResponse;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 
 /**
@@ -480,9 +479,9 @@ function locale_translation_manual_status() {
   // Execute a batch if required. A batch is only used when remote files
   // are checked.
   if (batch_get()) {
-    return batch_process('admin/reports/translations');
+    batch_process('admin/reports/translations');
   }
-  return new RedirectResponse(url('admin/reports/translations', array('absolute' => TRUE)));
+  drupal_goto('admin/reports/translations');
 }
 
 /**
diff --git a/core/modules/node/lib/Drupal/node/Form/DeleteMultiple.php b/core/modules/node/lib/Drupal/node/Form/DeleteMultiple.php
index 7a43181..3cb38bf 100644
--- a/core/modules/node/lib/Drupal/node/Form/DeleteMultiple.php
+++ b/core/modules/node/lib/Drupal/node/Form/DeleteMultiple.php
@@ -12,7 +12,6 @@
 use Drupal\Core\Entity\EntityManager;
 use Drupal\Component\Utility\String;
 use Drupal\user\TempStoreFactory;
-use Symfony\Component\HttpFoundation\RedirectResponse;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -98,7 +97,7 @@ public function getConfirmText() {
   public function buildForm(array $form, array &$form_state) {
     $this->nodes = $this->tempStoreFactory->get('node_multiple_delete_confirm')->get($GLOBALS['user']->uid);
     if (empty($this->nodes)) {
-      return new RedirectResponse(url($this->getCancelPath(), array('absolute' => TRUE)));
+      drupal_goto($this->getCancelPath());
     }
 
     $form['nodes'] = array(
diff --git a/core/modules/node/lib/Drupal/node/Plugin/views/wizard/Node.php b/core/modules/node/lib/Drupal/node/Plugin/views/wizard/Node.php
index db8b858..8d69811 100644
--- a/core/modules/node/lib/Drupal/node/Plugin/views/wizard/Node.php
+++ b/core/modules/node/lib/Drupal/node/Plugin/views/wizard/Node.php
@@ -278,11 +278,11 @@ protected function buildFilters(&$form, &$form_state) {
     $tag_fields = array();
     foreach ($bundles as $bundle) {
       foreach (field_info_instances($this->entity_type, $bundle) as $instance) {
-        $widget = entity_get_form_display($instance['entity_type'], $instance['bundle'], 'default')->getComponent($instance['field_name']);
+        $widget = entity_get_form_display($instance->entity_type, $instance->bundle, 'default')->getComponent($instance->getFieldName());
         // We define "tag-like" taxonomy fields as ones that use the
         // "Autocomplete term widget (tagging)" widget.
         if ($widget['type'] == 'taxonomy_autocomplete') {
-          $tag_fields[] = $instance['field_name'];
+          $tag_fields[] = $instance->getFieldName();
         }
       }
     }
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeTokenReplaceTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeTokenReplaceTest.php
index 90b7493..4d6c50b 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeTokenReplaceTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeTokenReplaceTest.php
@@ -54,8 +54,8 @@ function testNodeTokenReplacement() {
     $tests['[node:type]'] = 'article';
     $tests['[node:type-name]'] = 'Article';
     $tests['[node:title]'] = check_plain($node->title);
-    $tests['[node:body]'] = text_sanitize($instance['settings']['text_processing'], $node->langcode, $node->body[$node->langcode][0], 'value');
-    $tests['[node:summary]'] = text_sanitize($instance['settings']['text_processing'], $node->langcode, $node->body[$node->langcode][0], 'summary');
+    $tests['[node:body]'] = text_sanitize($instance->settings['text_processing'], $node->langcode, $node->body[$node->langcode][0], 'value');
+    $tests['[node:summary]'] = text_sanitize($instance->settings['text_processing'], $node->langcode, $node->body[$node->langcode][0], 'summary');
     $tests['[node:langcode]'] = check_plain($node->langcode);
     $tests['[node:url]'] = url('node/' . $node->nid, $url_options);
     $tests['[node:edit-url]'] = url('node/' . $node->nid . '/edit', $url_options);
@@ -96,7 +96,7 @@ function testNodeTokenReplacement() {
 
     // Generate and test sanitized token - use full body as expected value.
     $tests = array();
-    $tests['[node:summary]'] = text_sanitize($instance['settings']['text_processing'], $node->langcode, $node->body[$node->langcode][0], 'value');
+    $tests['[node:summary]'] = text_sanitize($instance->settings['text_processing'], $node->langcode, $node->body[$node->langcode][0], 'value');
 
     // Test to make sure that we generated something for each token.
     $this->assertFalse(in_array(0, array_map('strlen', $tests)), 'No empty tokens generated for node without a summary.');
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeTypeTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeTypeTest.php
index 6a5b5f6..2519eeb 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeTypeTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeTypeTest.php
@@ -84,7 +84,7 @@ function testNodeTypeEditing() {
     $this->drupalLogin($web_user);
 
     $instance = field_info_instance('node', 'body', 'page');
-    $this->assertEqual($instance['label'], 'Body', 'Body field was found.');
+    $this->assertEqual($instance->label(), 'Body', 'Body field was found.');
 
     // Verify that title and body fields are displayed.
     $this->drupalGet('node/add/page');
diff --git a/core/modules/node/node.pages.inc b/core/modules/node/node.pages.inc
index a731f40..f81210e 100644
--- a/core/modules/node/node.pages.inc
+++ b/core/modules/node/node.pages.inc
@@ -10,7 +10,6 @@
  */
 
 use Drupal\Core\Entity\EntityInterface;
-use Symfony\Component\HttpFoundation\RedirectResponse;
 
 /**
  * Page callback: Displays add content links for available content types.
@@ -35,7 +34,7 @@ function node_add_page() {
   // Bypass the node/add listing if only one content type is available.
   if (count($content) == 1) {
     $type = array_shift($content);
-    return new RedirectResponse(url('node/add/' . $type->type, array('absolute' => TRUE)));
+    drupal_goto('node/add/' . $type->type);
   }
   return array('#theme' => 'node_add_list', '#content' => $content);
 }
diff --git a/core/modules/node/node.tokens.inc b/core/modules/node/node.tokens.inc
index 241b83b..48f33f1 100644
--- a/core/modules/node/node.tokens.inc
+++ b/core/modules/node/node.tokens.inc
@@ -143,11 +143,11 @@ function node_tokens($type, $tokens, array $data = array(), array $options = arr
 
             // If the summary was requested and is not empty, use it.
             if ($name == 'summary' && !empty($items[0]['summary'])) {
-              $output = $sanitize ? text_sanitize($instance['settings']['text_processing'], $field_langcode, $items[0], 'summary') : $items[0]['summary'];
+              $output = $sanitize ? text_sanitize($instance->settings['text_processing'], $field_langcode, $items[0], 'summary') : $items[0]['summary'];
             }
             // Attempt to provide a suitable version of the 'body' field.
             else {
-              $output = $sanitize ? text_sanitize($instance['settings']['text_processing'], $field_langcode, $items[0], 'value') : $items[0]['value'];
+              $output = $sanitize ? text_sanitize($instance->settings['text_processing'], $field_langcode, $items[0], 'value') : $items[0]['value'];
               // A summary was requested.
               if ($name == 'summary') {
                 // Generate an optionally trimmed summary of the body field.
@@ -163,7 +163,7 @@ function node_tokens($type, $tokens, array $data = array(), array $options = arr
                   $length = $settings['trim_length'];
                 }
 
-                $output = text_summary($output, $instance['settings']['text_processing'] ? $items[0]['format'] : NULL, $length);
+                $output = text_summary($output, $instance->settings['text_processing'] ? $items[0]['format'] : NULL, $length);
               }
             }
             $replacements[$original] = $output;
diff --git a/core/modules/number/lib/Drupal/number/Plugin/field/formatter/DefaultNumberFormatter.php b/core/modules/number/lib/Drupal/number/Plugin/field/formatter/DefaultNumberFormatter.php
index 8188dc1..7e6429c 100644
--- a/core/modules/number/lib/Drupal/number/Plugin/field/formatter/DefaultNumberFormatter.php
+++ b/core/modules/number/lib/Drupal/number/Plugin/field/formatter/DefaultNumberFormatter.php
@@ -72,8 +72,8 @@ public function viewElements(EntityInterface $entity, $langcode, array $items) {
 
       // Account for prefix and suffix.
       if ($this->getSetting('prefix_suffix')) {
-        $prefixes = isset($instance['settings']['prefix']) ? array_map('field_filter_xss', explode('|', $instance['settings']['prefix'])) : array('');
-        $suffixes = isset($instance['settings']['suffix']) ? array_map('field_filter_xss', explode('|', $instance['settings']['suffix'])) : array('');
+        $prefixes = isset($instance->settings['prefix']) ? array_map('field_filter_xss', explode('|', $instance->settings['prefix'])) : array('');
+        $suffixes = isset($instance->settings['suffix']) ? array_map('field_filter_xss', explode('|', $instance->settings['suffix'])) : array('');
         $prefix = (count($prefixes) > 1) ? format_plural($item['value'], $prefixes[0], $prefixes[1]) : $prefixes[0];
         $suffix = (count($suffixes) > 1) ? format_plural($item['value'], $suffixes[0], $suffixes[1]) : $suffixes[0];
         $output = $prefix . $output . $suffix;
diff --git a/core/modules/number/lib/Drupal/number/Tests/NumberFieldTest.php b/core/modules/number/lib/Drupal/number/Tests/NumberFieldTest.php
index 904509c..2def20b 100644
--- a/core/modules/number/lib/Drupal/number/Tests/NumberFieldTest.php
+++ b/core/modules/number/lib/Drupal/number/Tests/NumberFieldTest.php
@@ -94,7 +94,7 @@ function testNumberDecimalField() {
     // Display creation form.
     $this->drupalGet('entity_test/add');
     $langcode = Language::LANGCODE_NOT_SPECIFIED;
-    $this->assertFieldByName("{$this->field['field_name']}[$langcode][0][value]", '', 'Widget is displayed');
+    $this->assertFieldByName("{$this->field->id()}[$langcode][0][value]", '', 'Widget is displayed');
     $this->assertRaw('placeholder="0.00"');
 
     // Submit a signed decimal value within the allowed precision and scale.
@@ -102,7 +102,7 @@ function testNumberDecimalField() {
     $edit = array(
       'user_id' => 1,
       'name' => $this->randomName(),
-      "{$this->field['field_name']}[$langcode][0][value]" => $value,
+      "{$this->field->id()}[$langcode][0][value]" => $value,
     );
     $this->drupalPost(NULL, $edit, t('Save'));
     preg_match('|entity_test/manage/(\d+)/edit|', $this->url, $match);
@@ -122,10 +122,10 @@ function testNumberDecimalField() {
     foreach ($wrong_entries as $wrong_entry) {
       $this->drupalGet('entity_test/add');
       $edit = array(
-        "{$this->field['field_name']}[$langcode][0][value]" => $wrong_entry,
+        "{$this->field->id()}[$langcode][0][value]" => $wrong_entry,
       );
       $this->drupalPost(NULL, $edit, t('Save'));
-      $this->assertRaw(t('%name must be a number.', array('%name' => $this->field['field_name'])), 'Correctly failed to save decimal value with more than one decimal point.');
+      $this->assertRaw(t('%name must be a number.', array('%name' => $this->field->id())), 'Correctly failed to save decimal value with more than one decimal point.');
     }
 
     // Try to create entries with minus sign not in the first position.
@@ -140,10 +140,10 @@ function testNumberDecimalField() {
     foreach ($wrong_entries as $wrong_entry) {
       $this->drupalGet('entity_test/add');
       $edit = array(
-        "{$this->field['field_name']}[$langcode][0][value]" => $wrong_entry,
+        "{$this->field->id()}[$langcode][0][value]" => $wrong_entry,
       );
       $this->drupalPost(NULL, $edit, t('Save'));
-      $this->assertRaw(t('%name must be a number.', array('%name' => $this->field['field_name'])), 'Correctly failed to save decimal value with minus sign in the wrong position.');
+      $this->assertRaw(t('%name must be a number.', array('%name' => $this->field->id())), 'Correctly failed to save decimal value with minus sign in the wrong position.');
     }
   }
 
diff --git a/core/modules/number/number.install b/core/modules/number/number.install
index 3c4ae7f..4520c95 100644
--- a/core/modules/number/number.install
+++ b/core/modules/number/number.install
@@ -9,7 +9,7 @@
  * Implements hook_field_schema().
  */
 function number_field_schema($field) {
-  switch ($field['type']) {
+  switch ($field->type) {
     case 'number_integer' :
       $columns = array(
         'value' => array(
@@ -32,8 +32,8 @@ function number_field_schema($field) {
       $columns = array(
         'value' => array(
           'type' => 'numeric',
-          'precision' => $field['settings']['precision'],
-          'scale' => $field['settings']['scale'],
+          'precision' => $field->settings['precision'],
+          'scale' => $field->settings['scale'],
           'not null' => FALSE
         ),
       );
diff --git a/core/modules/number/number.module b/core/modules/number/number.module
index 1504e4a..92a470d 100644
--- a/core/modules/number/number.module
+++ b/core/modules/number/number.module
@@ -60,7 +60,7 @@ function number_field_settings_form($field, $instance) {
   $settings = $field['settings'];
   $form = array();
 
-  if ($field['type'] == 'number_decimal') {
+  if ($field->type == 'number_decimal') {
     $form['precision'] = array(
       '#type' => 'select',
       '#title' => t('Precision'),
@@ -86,7 +86,7 @@ function number_field_settings_form($field, $instance) {
  * Implements hook_field_instance_settings_form().
  */
 function number_field_instance_settings_form($field, $instance) {
-  $settings = $instance['settings'];
+  $settings = $instance->settings;
 
   $form['min'] = array(
     '#type' => 'textfield',
@@ -130,16 +130,16 @@ function number_field_instance_settings_form($field, $instance) {
 function number_field_validate(EntityInterface $entity = NULL, $field, $instance, $langcode, $items, &$errors) {
   foreach ($items as $delta => $item) {
     if ($item['value'] != '') {
-      if (is_numeric($instance['settings']['min']) && $item['value'] < $instance['settings']['min']) {
-        $errors[$field['field_name']][$langcode][$delta][] = array(
+      if (is_numeric($instance->settings['min']) && $item['value'] < $instance->settings['min']) {
+        $errors[$field->id()][$langcode][$delta][] = array(
           'error' => 'number_min',
-          'message' => t('%name: the value may be no less than %min.', array('%name' => $instance['label'], '%min' => $instance['settings']['min'])),
+          'message' => t('%name: the value may be no less than %min.', array('%name' => $instance->label(), '%min' => $instance->settings['min'])),
         );
       }
-      if (is_numeric($instance['settings']['max']) && $item['value'] > $instance['settings']['max']) {
-        $errors[$field['field_name']][$langcode][$delta][] = array(
+      if (is_numeric($instance->settings['max']) && $item['value'] > $instance->settings['max']) {
+        $errors[$field->id()][$langcode][$delta][] = array(
           'error' => 'number_max',
-          'message' => t('%name: the value may be no greater than %max.', array('%name' => $instance['label'], '%max' => $instance['settings']['max'])),
+          'message' => t('%name: the value may be no greater than %max.', array('%name' => $instance->label(), '%max' => $instance->settings['max'])),
         );
       }
     }
@@ -150,12 +150,12 @@ function number_field_validate(EntityInterface $entity = NULL, $field, $instance
  * Implements hook_field_presave().
  */
 function number_field_presave(EntityInterface $entity, $field, $instance, $langcode, &$items) {
-  if ($field['type'] == 'number_decimal') {
+  if ($field->type == 'number_decimal') {
     // Let PHP round the value to ensure consistent behavior across storage
     // backends.
     foreach ($items as $delta => $item) {
       if (isset($item['value'])) {
-        $items[$delta]['value'] = round($item['value'], $field['settings']['scale']);
+        $items[$delta]['value'] = round($item['value'], $field->settings['scale']);
       }
     }
   }
diff --git a/core/modules/options/lib/Drupal/options/Tests/OptionsFieldTest.php b/core/modules/options/lib/Drupal/options/Tests/OptionsFieldTest.php
index 218e413..7125de6 100644
--- a/core/modules/options/lib/Drupal/options/Tests/OptionsFieldTest.php
+++ b/core/modules/options/lib/Drupal/options/Tests/OptionsFieldTest.php
@@ -70,7 +70,7 @@ function testUpdateAllowedValues() {
     $this->assertTrue(empty($form[$this->fieldName][$langcode][3]), 'Option 3 does not exist');
 
     // Completely new options appear.
-    $this->field['settings']['allowed_values'] = array(10 => 'Update', 20 => 'Twenty');
+    $this->field->settings['allowed_values'] = array(10 => 'Update', 20 => 'Twenty');
     $this->field->save();
     $form = \Drupal::entityManager()->getForm($entity);
     $this->assertTrue(empty($form[$this->fieldName][$langcode][1]), 'Option 1 does not exist');
diff --git a/core/modules/options/lib/Drupal/options/Tests/OptionsFieldUITest.php b/core/modules/options/lib/Drupal/options/Tests/OptionsFieldUITest.php
index d34f178..cee6d0f 100644
--- a/core/modules/options/lib/Drupal/options/Tests/OptionsFieldUITest.php
+++ b/core/modules/options/lib/Drupal/options/Tests/OptionsFieldUITest.php
@@ -232,9 +232,9 @@ function testOptionsAllowedValuesBoolean() {
     $this->assertFieldByName('on', $on, t("The 'On' value is stored correctly."));
     $this->assertFieldByName('off', $off, t("The 'Off' value is stored correctly."));
     $field = field_info_field($this->field_name);
-    $this->assertEqual($field['settings']['allowed_values'], $allowed_values, 'The allowed value is correct');
-    $this->assertFalse(isset($field['settings']['on']), 'The on value is not saved into settings');
-    $this->assertFalse(isset($field['settings']['off']), 'The off value is not saved into settings');
+    $this->assertEqual($field->settings['allowed_values'], $allowed_values, 'The allowed value is correct');
+    $this->assertFalse(isset($field->settings['on']), 'The on value is not saved into settings');
+    $this->assertFalse(isset($field->settings['off']), 'The off value is not saved into settings');
   }
 
   /**
@@ -281,7 +281,7 @@ protected function createOptionsField($type) {
    *   element.
    * @param $result
    *   Either an expected resulting array in
-   *   $field['settings']['allowed_values'], or an expected error message.
+   *   $field->settings['allowed_values'], or an expected error message.
    * @param $message
    *   Message to display.
    */
@@ -295,7 +295,7 @@ function assertAllowedValuesInput($input_string, $result, $message) {
     else {
       field_info_cache_clear();
       $field = field_info_field($this->field_name);
-      $this->assertIdentical($field['settings']['allowed_values'], $result, $message);
+      $this->assertIdentical($field->settings['allowed_values'], $result, $message);
     }
   }
 
diff --git a/core/modules/options/lib/Drupal/options/Tests/OptionsWidgetsTest.php b/core/modules/options/lib/Drupal/options/Tests/OptionsWidgetsTest.php
index 8d335c3..05f22f8 100644
--- a/core/modules/options/lib/Drupal/options/Tests/OptionsWidgetsTest.php
+++ b/core/modules/options/lib/Drupal/options/Tests/OptionsWidgetsTest.php
@@ -296,7 +296,7 @@ function testSelectListSingle() {
     // Submit form: select invalid 'none' option.
     $edit = array("card_1[$langcode]" => '_none');
     $this->drupalPost(NULL, $edit, t('Save'));
-    $this->assertRaw(t('!title field is required.', array('!title' => $instance['field_name'])), 'Cannot save a required field when selecting "none" from the select list.');
+    $this->assertRaw(t('!title field is required.', array('!title' => $instance->getFieldName())), 'Cannot save a required field when selecting "none" from the select list.');
 
     // Submit form: select first option.
     $edit = array("card_1[$langcode]" => 0);
@@ -326,8 +326,8 @@ function testSelectListSingle() {
 
     // Test optgroups.
 
-    $this->card_1['settings']['allowed_values'] = array();
-    $this->card_1['settings']['allowed_values_function'] = 'options_test_allowed_values_callback';
+    $this->card_1->settings['allowed_values'] = array();
+    $this->card_1->settings['allowed_values_function'] = 'options_test_allowed_values_callback';
     $this->card_1->save();
 
     // Display form: with no field data, nothing is selected
@@ -535,7 +535,7 @@ function testOnOffCheckbox() {
 
     // Create a test field instance.
     $fieldUpdate = $this->bool;
-    $fieldUpdate['settings']['allowed_values'] = array(0 => 0, 1 => 'MyOnValue');
+    $fieldUpdate->settings['allowed_values'] = array(0 => 0, 1 => 'MyOnValue');
     $fieldUpdate->save();
     entity_create('field_instance', array(
       'field_name' => $this->bool['field_name'],
diff --git a/core/modules/options/options.install b/core/modules/options/options.install
index 6c2c8af..ae08db2 100644
--- a/core/modules/options/options.install
+++ b/core/modules/options/options.install
@@ -9,7 +9,7 @@
  * Implements hook_field_schema().
  */
 function options_field_schema($field) {
-  switch ($field['type']) {
+  switch ($field->type) {
     case 'list_text':
       $columns = array(
         'value' => array(
diff --git a/core/modules/options/options.module b/core/modules/options/options.module
index 88a2b48..57e01a8 100644
--- a/core/modules/options/options.module
+++ b/core/modules/options/options.module
@@ -71,7 +71,7 @@ function options_field_info() {
 function options_field_settings_form($field, $instance) {
   $settings = $field['settings'];
 
-  switch ($field['type']) {
+  switch ($field->type) {
     case 'list_integer':
     case 'list_float':
     case 'list_text':
@@ -83,12 +83,12 @@ function options_field_settings_form($field, $instance) {
         '#element_validate' => array('options_field_settings_form_validate_allowed_values'),
         '#field_has_data' => $field->hasData(),
         '#field' => $field,
-        '#field_type' => $field['type'],
+        '#field_type' => $field->type,
         '#access' => empty($settings['allowed_values_function']),
       );
 
       $description = '<p>' . t('The possible values this field can contain. Enter one value per line, in the format key|label.');
-      if ($field['type'] == 'list_integer' || $field['type'] == 'list_float') {
+      if ($field->type == 'list_integer' || $field->type == 'list_float') {
         $description .= '<br/>' . t('The key is the stored value, and must be numeric. The label will be used in displayed values and edit forms.');
         $description .= '<br/>' . t('The label is optional: if a line contains a single number, it will be used as key and label.');
         $description .= '<br/>' . t('Lists of labels are also accepted (one label per line), only if the field does not hold any values yet. Numeric keys will be automatically generated from the positions in the list.');
@@ -143,12 +143,12 @@ function options_field_settings_form($field, $instance) {
   }
 
   // Alter the description for allowed values depending on the widget type.
-  if ($instance['widget']['type'] == 'options_onoff') {
+  /*if ($instance['widget']['type'] == 'options_onoff') {
     $form['allowed_values']['#description'] .= '<p>' . t("For a 'single on/off checkbox' widget, define the 'off' value first, then the 'on' value in the <strong>Allowed values</strong> section. Note that the checkbox will be labeled with the label of the 'on' value.") . '</p>';
   }
   elseif ($instance['widget']['type'] == 'options_buttons') {
     $form['allowed_values']['#description'] .= '<p>' . t("The 'checkboxes/radio buttons' widget will display checkboxes if the <em>Number of values</em> option is greater than 1 for this field, otherwise radios will be displayed.") . '</p>';
-  }
+  }*/
   $form['allowed_values']['#description'] .= '<p>' . t('Allowed HTML tags in labels: @tags', array('@tags' => _field_filter_xss_display_allowed_tags())) . '</p>';
 
   $form['allowed_values_function'] = array(
@@ -168,10 +168,10 @@ function options_field_settings_form($field, $instance) {
 function options_field_settings_form_validate_allowed_values($element, &$form_state) {
   $field = $element['#field'];
   $has_data = $element['#field_has_data'];
-  $field_type = $field['type'];
+  $field_type = $field->type;
   $generate_keys = ($field_type == 'list_integer' || $field_type == 'list_float') && !$has_data;
 
-  $values = options_extract_allowed_values($element['#value'], $field['type'], $generate_keys);
+  $values = options_extract_allowed_values($element['#value'], $field->type, $generate_keys);
 
   if (!is_array($values)) {
     form_error($element, t('Allowed values list: invalid input.'));
@@ -195,7 +195,7 @@ function options_field_settings_form_validate_allowed_values($element, &$form_st
 
     // Prevent removing values currently in use.
     if ($has_data) {
-      $lost_keys = array_diff(array_keys($field['settings']['allowed_values']), array_keys($values));
+      $lost_keys = array_diff(array_keys($field->settings['allowed_values']), array_keys($values));
       if (_options_values_in_use($field, $lost_keys)) {
         form_error($element, t('Allowed values list: some values are being removed while currently in use.'));
       }
@@ -369,11 +369,11 @@ function options_allowed_values_string($values) {
  * Implements hook_field_update_forbid().
  */
 function options_field_update_forbid($field, $prior_field) {
-  if ($field['module'] == 'options' && $field->hasData()) {
+  if ($field->module == 'options' && $field->hasData()) {
     // Forbid any update that removes allowed values with actual data.
-    $lost_keys = array_diff(array_keys($prior_field['settings']['allowed_values']), array_keys($field['settings']['allowed_values']));
+    $lost_keys = array_diff(array_keys($prior_field->settings['allowed_values']), array_keys($field->settings['allowed_values']));
     if (_options_values_in_use($field, $lost_keys)) {
-      throw new FieldUpdateForbiddenException(t('A list field (@field_name) with existing data cannot have its keys changed.', array('@field_name' => $field['field_name'])));
+      throw new FieldUpdateForbiddenException(t('A list field (@field_name) with existing data cannot have its keys changed.', array('@field_name' => $field->id())));
     }
   }
 }
@@ -383,11 +383,11 @@ function options_field_update_forbid($field, $prior_field) {
  */
 function _options_values_in_use($field, $values) {
   if ($values) {
-    $field = field_info_field_by_id($field['uuid']);
+    $field = field_info_field_by_id($field->uuid);
     $factory = Drupal::service('entity.query');
-    foreach ($field['bundles'] as $entity_type => $bundle) {
+    foreach ($field->getBundles() as $entity_type => $bundle) {
       $result = $factory->get($entity_type)
-        ->condition($field['field_name'] . '.value', $values)
+        ->condition($field->id() . '.value', $values)
         ->count()
         ->accessCheck(FALSE)
         ->range(0, 1)
@@ -421,9 +421,9 @@ function options_field_validate(EntityInterface $entity = NULL, $field, $instanc
   foreach ($items as $delta => $item) {
     if (!empty($item['value'])) {
       if (!empty($allowed_values) && !isset($allowed_values[$item['value']])) {
-        $errors[$field['field_name']][$langcode][$delta][] = array(
+        $errors[$field->id()][$langcode][$delta][] = array(
           'error' => 'list_illegal_value',
-          'message' => t('%name: illegal value.', array('%name' => $instance['label'])),
+          'message' => t('%name: illegal value.', array('%name' => $instance->label())),
         );
       }
     }
diff --git a/core/modules/overlay/lib/Drupal/overlay/EventSubscriber/OverlaySubscriber.php b/core/modules/overlay/lib/Drupal/overlay/EventSubscriber/OverlaySubscriber.php
index 18d9086..b6c380e 100644
--- a/core/modules/overlay/lib/Drupal/overlay/EventSubscriber/OverlaySubscriber.php
+++ b/core/modules/overlay/lib/Drupal/overlay/EventSubscriber/OverlaySubscriber.php
@@ -8,7 +8,6 @@
 namespace Drupal\overlay\EventSubscriber;
 
 use Drupal\Core\ContentNegotiation;
-use Drupal\Core\Routing\PathBasedGeneratorInterface;
 use Drupal\user\UserData;
 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
 use Symfony\Component\HttpFoundation\RedirectResponse;
@@ -36,26 +35,16 @@ class OverlaySubscriber implements EventSubscriberInterface {
   protected $userData;
 
   /**
-   * The url generator service.
-   *
-   * @var \Drupal\Core\Routing\PathBasedGeneratorInterface
-   */
-  protected $urlGenerator;
-
-  /**
    * Constructs an OverlaySubscriber object.
    *
    * @param \Drupal\Core\ContentNegotiation $negotiation
    *   The content negotiation service.
    * @param \Drupal\user\UserData $user_data
    *   The user.data service.
-   * @param \Drupal\Core\Routing\PathBasedGeneratorInterface $url_generator
-   *   The url generator service.
    */
-  public function __construct(ContentNegotiation $negotiation, UserData $user_data, PathBasedGeneratorInterface $url_generator) {
+  public function __construct(ContentNegotiation $negotiation, UserData $user_data) {
     $this->negotiation = $negotiation;
     $this->userData = $user_data;
-    $this->urlGenerator = $url_generator;
   }
 
   /**
@@ -86,12 +75,7 @@ public function onRequest(GetResponseEvent $event) {
       // <front>#overlay=admin/modules to actually enable the overlay.
       if (isset($_SESSION['overlay_enable_redirect']) && $_SESSION['overlay_enable_redirect']) {
         unset($_SESSION['overlay_enable_redirect']);
-        $url = $this->urlGenerator
-          ->generateFromPath('<front>', array(
-            'fragment' => 'overlay=' . $current_path,
-            'absolute' => TRUE,
-          ));
-        $response = new RedirectResponse($url);
+        $response = new RedirectResponse(url('<front>', array('fragment' => 'overlay=' . $current_path, 'absolute' => TRUE)));
         $event->setResponse($response);
       }
 
@@ -150,32 +134,6 @@ public function onResponse(FilterResponseEvent $event) {
           }
         }
       }
-      $response = $event->getResponse();
-      if ($response instanceOf RedirectResponse) {
-        $path = $response->getTargetUrl();
-        // The authorize.php script bootstraps Drupal to a very low level, where
-        // the PHP code that is necessary to close the overlay properly will not
-        // be loaded. Therefore, if we are redirecting to authorize.php inside
-        // the overlay, instead redirect back to the current page with
-        // instructions to close the overlay there before redirecting to the
-        // final destination.
-        $options = array('absolute' => TRUE);
-        if ($path == system_authorized_get_url($options) || $path == system_authorized_batch_processing_url($options)) {
-          $_SESSION['overlay_close_dialog'] = array($path, $options);
-          $path = current_path();
-          $options = drupal_get_query_parameters();
-        }
-
-        // If the current page request is inside the overlay, add ?render=overlay
-        // to the new path, so that it appears correctly inside the overlay.
-        if (isset($options['query'])) {
-          $options['query'] += array('render' => 'overlay');
-        }
-        else {
-          $options['query'] = array('render' => 'overlay');
-        }
-        $response->setTargetUrl($this->urlGenerator->generateFromPath($path, $options));
-      }
     }
   }
 
diff --git a/core/modules/overlay/overlay.module b/core/modules/overlay/overlay.module
index 180ea97..103a810 100644
--- a/core/modules/overlay/overlay.module
+++ b/core/modules/overlay/overlay.module
@@ -5,7 +5,6 @@
  * Displays the Drupal administration interface in an overlay.
  */
 
-use Symfony\Component\HttpFoundation\RedirectResponse;
 use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 use Drupal\block\Plugin\Core\Entity\Block;
@@ -178,6 +177,34 @@ function overlay_library_info() {
 }
 
 /**
+ * Implements hook_drupal_goto_alter().
+ */
+function overlay_drupal_goto_alter(&$path, &$options, &$http_response_code) {
+  if (overlay_get_mode() == 'child') {
+    // The authorize.php script bootstraps Drupal to a very low level, where
+    // the PHP code that is necessary to close the overlay properly will not be
+    // loaded. Therefore, if we are redirecting to authorize.php inside the
+    // overlay, instead redirect back to the current page with instructions to
+    // close the overlay there before redirecting to the final destination; see
+    // overlay_init().
+    if ($path == system_authorized_get_url() || $path == system_authorized_batch_processing_url()) {
+      $_SESSION['overlay_close_dialog'] = array($path, $options);
+      $path = current_path();
+      $options = drupal_get_query_parameters();
+    }
+
+    // If the current page request is inside the overlay, add ?render=overlay
+    // to the new path, so that it appears correctly inside the overlay.
+    if (isset($options['query'])) {
+      $options['query'] += array('render' => 'overlay');
+    }
+    else {
+      $options['query'] = array('render' => 'overlay');
+    }
+  }
+}
+
+/**
  * Implements hook_batch_alter().
  *
  * If the current page request is inside the overlay, add ?render=overlay to
@@ -266,7 +293,7 @@ function overlay_user_dismiss_message() {
   Drupal::service('user.data')->set('overlay', $user->uid, 'message_dismissed', 1);
   drupal_set_message(t('The message has been dismissed. You can change your overlay settings at any time by visiting your profile page.'));
   // Destination is normally given. Go to the user profile as a fallback.
-  return new RedirectResponse(url('user/' . $user->uid . '/edit', array('absolute' => TRUE)));
+  drupal_goto('user/' . $user->uid . '/edit');
 }
 
 /**
diff --git a/core/modules/overlay/overlay.services.yml b/core/modules/overlay/overlay.services.yml
index b15e6cd..7ab943f 100644
--- a/core/modules/overlay/overlay.services.yml
+++ b/core/modules/overlay/overlay.services.yml
@@ -3,4 +3,4 @@ services:
     class: Drupal\overlay\EventSubscriber\OverlaySubscriber
     tags:
       - { name: event_subscriber }
-    arguments: ['@content_negotiation', '@user.data', '@url_generator']
+    arguments: ['@content_negotiation', '@user.data']
diff --git a/core/modules/rest/lib/Drupal/rest/LinkManager/RelationLinkManager.php b/core/modules/rest/lib/Drupal/rest/LinkManager/RelationLinkManager.php
index 0e3fd91..d71d6ce 100644
--- a/core/modules/rest/lib/Drupal/rest/LinkManager/RelationLinkManager.php
+++ b/core/modules/rest/lib/Drupal/rest/LinkManager/RelationLinkManager.php
@@ -75,13 +75,13 @@ protected function writeCache() {
     $data = array();
 
     foreach (field_info_fields() as $field_info) {
-      foreach ($field_info['bundles'] as $entity_type => $bundles) {
+      foreach ($field_info->getBundles() as $entity_type => $bundles) {
         foreach ($bundles as $bundle) {
-          $relation_uri = $this->getRelationUri($entity_type, $bundle, $field_info['field_name']);
+          $relation_uri = $this->getRelationUri($entity_type, $bundle, $field_info->id());
           $data[$relation_uri] = array(
             'entity_type' => $entity_type,
             'bundle' => $bundle,
-            'field_name' => $field_info['field_name'],
+            'field_name' => $field_info->id(),
           );
         }
       }
diff --git a/core/modules/search/search.pages.inc b/core/modules/search/search.pages.inc
index 646028a..aed41f6 100644
--- a/core/modules/search/search.pages.inc
+++ b/core/modules/search/search.pages.inc
@@ -6,7 +6,6 @@
  */
 
 use Drupal\Core\Language\Language;
-use Symfony\Component\HttpFoundation\RedirectResponse;
 
 /**
  * Page callback: Presents the search form and/or search results.
@@ -42,7 +41,7 @@ function search_view($module = NULL, $keys = '') {
     if ($keys) {
       $path .= '/' . $keys;
     }
-    return new RedirectResponse(url($path, array('absolute' => TRUE)));
+    drupal_goto($path);
   }
 
   // Default results output is an empty string.
diff --git a/core/modules/shortcut/shortcut.admin.inc b/core/modules/shortcut/shortcut.admin.inc
index 0671b2a..60dab60 100644
--- a/core/modules/shortcut/shortcut.admin.inc
+++ b/core/modules/shortcut/shortcut.admin.inc
@@ -5,7 +5,6 @@
  * Administrative page callbacks for the shortcut module.
  */
 
-use Symfony\Component\HttpFoundation\RedirectResponse;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 
 /**
@@ -499,7 +498,7 @@ function shortcut_link_add_inline($shortcut_set) {
     else {
       drupal_set_message(t('Unable to add a shortcut for %title.', array('%title' => $link['link_title'])));
     }
-    return new RedirectResponse(url('<front>', array('absolute' => TRUE)));
+    drupal_goto();
   }
 
   throw new AccessDeniedHttpException();
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/Form/SimpletestResultsForm.php b/core/modules/simpletest/lib/Drupal/simpletest/Form/SimpletestResultsForm.php
index 35c0ce6..50ee959 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/Form/SimpletestResultsForm.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/Form/SimpletestResultsForm.php
@@ -11,7 +11,6 @@
 use Drupal\Core\Database\Connection;
 use Drupal\Core\Form\FormInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
-use Symfony\Component\HttpFoundation\RedirectResponse;
 
 /**
  * Test results form for $test_id.
@@ -92,7 +91,9 @@ public function buildForm(array $form, array &$form_state, $test_id = NULL) {
 
     if (is_numeric($test_id) && !$results = $this->getResults($test_id)) {
       drupal_set_message(t('No test results to display.'), 'error');
-      return new RedirectResponse(url('admin/config/development/testing', array('absolute' => TRUE)));
+      drupal_goto('admin/config/development/testing');
+
+      return $form;
     }
 
     // Load all classes and include CSS.
diff --git a/core/modules/system/lib/Drupal/system/Tests/Common/GotoTest.php b/core/modules/system/lib/Drupal/system/Tests/Common/GotoTest.php
new file mode 100644
index 0000000..c9e3cfc
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/Common/GotoTest.php
@@ -0,0 +1,97 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\system\Tests\Common\GotoTest.
+ */
+
+namespace Drupal\system\Tests\Common;
+
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Tests drupal_goto() and hook_drupal_goto_alter().
+ */
+class GotoTest extends WebTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('common_test');
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Redirect functionality',
+      'description' => 'Tests the drupal_goto() and hook_drupal_goto_alter() functionality.',
+      'group' => 'Common',
+    );
+  }
+
+  /**
+   * Tests drupal_goto().
+   */
+  function testDrupalGoto() {
+    $this->drupalGet('common-test/drupal_goto/redirect');
+    $headers = $this->drupalGetHeaders(TRUE);
+    list(, $status) = explode(' ', $headers[0][':status'], 3);
+    $this->assertEqual($status, 302, 'Expected response code was sent.');
+    $this->assertText('drupal_goto', 'Drupal goto redirect succeeded.');
+    $this->assertEqual($this->getUrl(), url('common-test/drupal_goto', array('absolute' => TRUE)), 'Drupal goto redirected to expected URL.');
+
+    $this->drupalGet('common-test/drupal_goto/redirect_advanced');
+    $headers = $this->drupalGetHeaders(TRUE);
+    list(, $status) = explode(' ', $headers[0][':status'], 3);
+    $this->assertEqual($status, 301, 'Expected response code was sent.');
+    $this->assertText('drupal_goto', 'Drupal goto redirect succeeded.');
+    $this->assertEqual($this->getUrl(), url('common-test/drupal_goto', array('query' => array('foo' => '123'), 'absolute' => TRUE)), 'Drupal goto redirected to expected URL.');
+
+    // Test that drupal_goto() respects ?destination=xxx. Use a complicated URL
+    // to test that the path is encoded and decoded properly.
+    $destination = 'common-test/drupal_goto/destination?foo=%2525&bar=123';
+    $this->drupalGet('common-test/drupal_goto/redirect', array('query' => array('destination' => $destination)));
+    $this->assertText('drupal_goto', 'Drupal goto redirect with destination succeeded.');
+    $this->assertEqual($this->getUrl(), url('common-test/drupal_goto/destination', array('query' => array('foo' => '%25', 'bar' => '123'), 'absolute' => TRUE)), 'Drupal goto redirected to given query string destination.');
+
+    // Test that drupal_goto() respects ?destination=xxx with an absolute URL
+    // that points to this Drupal installation.
+    $destination = url('common-test/drupal_goto/alternative', array('absolute' => TRUE));
+    $this->drupalGet('common-test/drupal_goto/redirect', array('query' => array('destination' => $destination)));
+    $this->assertText('drupal_goto_alternative', 'Drupal goto redirect with absolute URL destination that points to this Drupal installation succeeded.');
+    $this->assertEqual($this->getUrl(), url('common-test/drupal_goto/alternative', array('absolute' => TRUE)), 'Drupal goto redirected to given query string destination with absolute URL that points to this Drupal installation.');
+
+    // Test that drupal_goto() fails to respect ?destination=xxx with an absolute URL
+    // that does not point to this Drupal installation.
+    $destination = 'http://example.com';
+    $this->drupalGet('common-test/drupal_goto/redirect', array('query' => array('destination' => $destination)));
+    $this->assertText('drupal_goto', 'Drupal goto fails to redirect with absolute URL destination that does not point to this Drupal installation.');
+    $this->assertNotEqual($this->getUrl(), $destination, 'Drupal goto failed to redirect to given query string destination with absolute URL that does not point to this Drupal installation.');
+  }
+
+  /**
+   * Tests hook_drupal_goto_alter().
+   */
+  function testDrupalGotoAlter() {
+    $this->drupalGet('common-test/drupal_goto/redirect_fail');
+
+    $this->assertNoText(t("Drupal goto failed to stop program"), 'Drupal goto stopped program.');
+    $this->assertNoText('drupal_goto_fail', 'Drupal goto redirect failed.');
+  }
+
+  /**
+   * Tests drupal_get_destination().
+   */
+  function testDrupalGetDestination() {
+    $query = $this->randomName(10);
+
+    // Verify that a 'destination' query string is used as destination.
+    $this->drupalGet('common-test/destination', array('query' => array('destination' => $query)));
+    $this->assertText('The destination: ' . $query, 'The given query string destination is determined as destination.');
+
+    // Verify that the current path is used as destination.
+    $this->drupalGet('common-test/destination', array('query' => array($query => NULL)));
+    $url = 'common-test/destination?' . $query;
+    $this->assertText('The destination: ' . $url, 'The current path is determined as destination.');
+  }
+}
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityQueryRelationshipTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityQueryRelationshipTest.php
index 7a40d9b..49192ef 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityQueryRelationshipTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityQueryRelationshipTest.php
@@ -84,7 +84,7 @@ public function setUp() {
       'field_name' => $this->fieldName,
       'type' => 'taxonomy_term_reference',
     );
-    $field['settings']['allowed_values']['vocabulary'] = $vocabulary->id();
+    $field->settings['allowed_values']['vocabulary'] = $vocabulary->id();
     entity_create('field_entity', $field)->save();
     // Third, create the instance.
     entity_create('field_instance', array(
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationFormTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationFormTest.php
index 80d00b8..89363ef 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationFormTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationFormTest.php
@@ -108,7 +108,7 @@ function testEntityFormLanguage() {
     $field->translatable = TRUE;
     $field->save();
     $field = field_info_field('body');
-    $this->assertTrue($field['translatable'], 'Field body is translatable.');
+    $this->assertTrue($field->translatable, 'Field body is translatable.');
 
     // Create a body translation and check the form language.
     $langcode2 = $this->langcodes[1];
diff --git a/core/modules/system/lib/Drupal/system/Tests/Upgrade/FieldUpgradePathTest.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/FieldUpgradePathTest.php
index ab3e56d..e7f6eac 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/FieldUpgradePathTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/FieldUpgradePathTest.php
@@ -65,7 +65,7 @@ public function testEntityDisplayUpgrade() {
 
     // Check that the display key in the instance data was removed.
     $body_instance = field_info_instance('node', 'body', 'article');
-    $this->assertTrue(!isset($body_instance['display']));
+    $this->assertTrue(!isset($body_instance->display));
 
     // Check that the 'language' extra field is configured as expected.
     $expected = array(
@@ -193,7 +193,7 @@ function testFieldUpgradeToConfig() {
     $uuid_key = key($deleted_fields);
     $deleted_field = $deleted_fields[$uuid_key];
     $this->assertEqual($deleted_field['uuid'], $uuid_key);
-    $this->assertEqual($deleted_field['id'], 'test_deleted_field');
+    $this->assertEqual($deleted_field->id(), 'test_deleted_field');
 
     // Check that the definition of a deleted instance is stored in state rather
     // than config.
@@ -202,10 +202,10 @@ function testFieldUpgradeToConfig() {
     // Assume there was only one deleted instance in the test database.
     $uuid_key = key($deleted_instances);
     $deleted_instance = $deleted_instances[$uuid_key];
-    $this->assertEqual($deleted_instance['uuid'], $uuid_key);
-    $this->assertEqual($deleted_instance['id'], 'node.article.test_deleted_field');
+    $this->assertEqual($deleted_instance->uuid, $uuid_key);
+    $this->assertEqual($deleted_instance->id, 'node.article.test_deleted_field');
     // The deleted field uuid and deleted instance field_uuid must match.
-    $this->assertEqual($deleted_field['uuid'], $deleted_instance['field_uuid']);
+    $this->assertEqual($deleted_field['uuid'], $deleted_instance->field_uuid);
 
     // Check that pre-existing deleted field values are read correctly.
     $entity = _field_create_entity_from_ids((object) array(
diff --git a/core/modules/system/lib/Drupal/system/Tests/Upgrade/UserPictureUpgradePathTest.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/UserPictureUpgradePathTest.php
index 376f1e9..bfed9eb 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/UserPictureUpgradePathTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/UserPictureUpgradePathTest.php
@@ -42,8 +42,8 @@ public function testUserPictureUpgrade() {
 
     // Retrieve the field instance and check for migrated settings.
     $instance = field_info_instance('user', 'user_picture', 'user');
-    $file = entity_load('file', $instance['settings']['default_image'][0]);
-    $this->assertIdentical($instance['settings']['default_image'][0], $file->id(), 'Default user picture has been migrated.');
+    $file = entity_load('file', $instance->settings['default_image'][0]);
+    $this->assertIdentical($instance->settings['default_image'][0], $file->id(), 'Default user picture has been migrated.');
     $this->assertEqual($file->getFileUri(), 'public://user_pictures_dir/druplicon.png', 'File id matches the uri expected.');
     $this->assertEqual($file->getFilename(), 'druplicon.png');
     $this->assertEqual($file->langcode->value, Language::LANGCODE_NOT_SPECIFIED);
@@ -55,10 +55,10 @@ public function testUserPictureUpgrade() {
     $field = field_info_field('user_picture');
     $this->assertTrue(isset($usage['image']['default_image'][$field['uuid']]));
 
-    $this->assertEqual($instance['settings']['max_resolution'], '800x800', 'User picture maximum resolution has been migrated.');
-    $this->assertEqual($instance['settings']['max_filesize'], '700 KB', 'User picture maximum filesize has been migrated.');
-    $this->assertEqual($instance['description'], 'These are user picture guidelines.', 'User picture guidelines are now the user picture field description.');
-    $this->assertEqual($instance['settings']['file_directory'], 'user_pictures_dir', 'User picture directory path has been migrated.');
+    $this->assertEqual($instance->settings['max_resolution'], '800x800', 'User picture maximum resolution has been migrated.');
+    $this->assertEqual($instance->settings['max_filesize'], '700 KB', 'User picture maximum filesize has been migrated.');
+    $this->assertEqual($instance->description, 'These are user picture guidelines.', 'User picture guidelines are now the user picture field description.');
+    $this->assertEqual($instance->settings['file_directory'], 'user_pictures_dir', 'User picture directory path has been migrated.');
 
     $display_options = entity_get_display('user', 'user', 'default')->getComponent('user_picture');
     $this->assertEqual($display_options['settings']['image_style'], 'thumbnail', 'User picture image style setting has been migrated.');
diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc
index c499692..583dc98 100644
--- a/core/modules/system/system.admin.inc
+++ b/core/modules/system/system.admin.inc
@@ -8,7 +8,6 @@
 use Drupal\Core\Ajax\AjaxResponse;
 use Drupal\Core\Ajax\ReplaceCommand;
 use Symfony\Component\HttpFoundation\JsonResponse;
-use Symfony\Component\HttpFoundation\RedirectResponse;
 use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 use Drupal\Core\Datetime\DrupalDateTime;
@@ -300,7 +299,7 @@ function system_theme_default() {
     else {
       drupal_set_message(t('The %theme theme was not found.', array('%theme' => $theme)), 'error');
     }
-    return new RedirectResponse(url('admin/appearance', array('absolute' => TRUE)));
+    drupal_goto('admin/appearance');
   }
   throw new AccessDeniedHttpException();
 }
@@ -1224,7 +1223,7 @@ function system_modules_uninstall_validate($form, &$form_state) {
   // Form submitted, but no modules selected.
   if (!count(array_filter($form_state['values']['uninstall']))) {
     drupal_set_message(t('No modules selected.'), 'error');
-    return new RedirectResponse(url('admin/modules/uninstall', array('absolute' => TRUE)));
+    drupal_goto('admin/modules/uninstall');
   }
 }
 
diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php
index e9e69c5..943e99a 100644
--- a/core/modules/system/system.api.php
+++ b/core/modules/system/system.api.php
@@ -3004,6 +3004,22 @@ function hook_install_tasks(&$install_state) {
 }
 
 /**
+ * Change the page the user is sent to by drupal_goto().
+ *
+ * @param $path
+ *   A Drupal path or a full URL.
+ * @param $options
+ *   An associative array of additional URL options to pass to url().
+ * @param $http_response_code
+ *   The HTTP status code to use for the redirection. See drupal_goto() for more
+ *   information.
+ */
+function hook_drupal_goto_alter(&$path, &$options, &$http_response_code) {
+  // A good addition to misery module.
+  $http_response_code = 500;
+}
+
+/**
  * Alter XHTML HEAD tags before they are rendered by drupal_get_html_head().
  *
  * Elements available to be altered are only those added using
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index abc9f9c..ea58a62 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -12,7 +12,6 @@
 use Drupal\Core\TypedData\Primitive;
 use Drupal\system\Plugin\Block\SystemMenuBlock;
 use Symfony\Component\HttpFoundation\JsonResponse;
-use Symfony\Component\HttpFoundation\RedirectResponse;
 use Symfony\Component\HttpFoundation\Response;
 use Guzzle\Http\Exception\BadResponseException;
 use Guzzle\Http\Exception\RequestException;
@@ -2348,7 +2347,7 @@ function _system_themes_access($theme) {
  * or to call system_authorized_init() and then redirect to authorize.php,
  * using the URL from system_authorized_get_url(). Redirecting yourself is
  * necessary when your authorized operation is being triggered by a form
- * submit handler, since calling redirecting in a submit handler is a bad
+ * submit handler, since calling drupal_goto() in a submit handler is a bad
  * idea, and you should instead set $form_state['redirect'].
  *
  * Once the SESSION is setup for the operation and the user is redirected to
@@ -2376,7 +2375,7 @@ function _system_themes_access($theme) {
  * not to assume any code exists. Example (system_authorized_run()):
  * @code
  *   system_authorized_init($callback, $file, $arguments, $page_title);
- *   return new RedirectResponse(system_authorized_get_url());
+ *   drupal_goto(system_authorized_get_url());
  * @endcode
  * Example (update_manager_install_form_submit()):
  * @code
@@ -2437,13 +2436,9 @@ function system_authorized_get_url(array $options = array()) {
 
 /**
  * Returns the URL for the authorize.php script when it is processing a batch.
- *
- * @param array $options
- *   Optional array of options to pass to url().
  */
-function system_authorized_batch_processing_url(array $options = array()) {
-  $options['query'] = array('batch' => '1');
-  return system_authorized_get_url($options);
+function system_authorized_batch_processing_url() {
+  return system_authorized_get_url(array('query' => array('batch' => '1')));
 }
 
 /**
@@ -2453,7 +2448,7 @@ function system_authorized_batch_processing_url(array $options = array()) {
  */
 function system_authorized_run($callback, $file, $arguments = array(), $page_title = NULL) {
   system_authorized_init($callback, $file, $arguments, $page_title);
-  return new RedirectResponse(system_authorized_get_url());
+  drupal_goto(system_authorized_get_url());
 }
 
 /**
@@ -2464,7 +2459,7 @@ function system_authorized_run($callback, $file, $arguments = array(), $page_tit
 function system_authorized_batch_process() {
   $finish_url = system_authorized_get_url();
   $process_url = system_authorized_batch_processing_url();
-  return batch_process($finish_url, $process_url);
+  batch_process($finish_url, $process_url);
 }
 
 /**
@@ -3375,7 +3370,7 @@ function system_admin_compact_mode() {
  */
 function system_admin_compact_page($mode = 'off') {
   user_cookie_save(array('admin_compact_mode' => ($mode == 'on')));
-  return new RedirectResponse(url('<front>', array('absolute' => TRUE)));
+  drupal_goto();
 }
 
 /**
diff --git a/core/modules/system/tests/modules/batch_test/batch_test.module b/core/modules/system/tests/modules/batch_test/batch_test.module
index 2c1bee2..85ee47c 100644
--- a/core/modules/system/tests/modules/batch_test/batch_test.module
+++ b/core/modules/system/tests/modules/batch_test/batch_test.module
@@ -294,7 +294,7 @@ function batch_test_nested_drupal_form_submit($value = 1) {
     array('_batch_test_nested_drupal_form_submit_callback', array($value)),
   );
   batch_set($batch);
-  return batch_process('batch-test/redirect');
+  batch_process('batch-test/redirect');
 }
 
 /**
@@ -338,7 +338,7 @@ function batch_test_no_form() {
   batch_test_stack(NULL, TRUE);
 
   batch_set(_batch_test_batch_1());
-  return batch_process('batch-test/redirect');
+  batch_process('batch-test/redirect');
 }
 
 /**
@@ -348,7 +348,7 @@ function batch_test_large_percentage() {
   batch_test_stack(NULL, TRUE);
 
   batch_set(_batch_test_batch_5());
-  return batch_process('batch-test/redirect');
+  batch_process('batch-test/redirect');
 }
 
 /**
@@ -506,7 +506,7 @@ function batch_test_theme_batch() {
     ),
   );
   batch_set($batch);
-  return batch_process('batch-test/redirect');
+  batch_process('batch-test/redirect');
 }
 
 /**
diff --git a/core/modules/system/tests/modules/common_test/common_test.module b/core/modules/system/tests/modules/common_test/common_test.module
index 83d19e0..0334219 100644
--- a/core/modules/system/tests/modules/common_test/common_test.module
+++ b/core/modules/system/tests/modules/common_test/common_test.module
@@ -9,6 +9,43 @@
  * Implements hook_menu().
  */
 function common_test_menu() {
+  $items['common-test/drupal_goto'] = array(
+    'title' => 'Drupal Goto',
+    'page callback' => 'common_test_drupal_goto_land',
+    'access arguments' => array('access content'),
+    'type' => MENU_CALLBACK,
+  );
+  $items['common-test/drupal_goto/alternative'] = array(
+    'title' => 'Drupal Goto',
+    'page callback' => 'common_test_drupal_goto_land_alternative',
+    'access arguments' => array('access content'),
+    'type' => MENU_CALLBACK,
+  );
+  $items['common-test/drupal_goto/fail'] = array(
+    'title' => 'Drupal Goto',
+    'page callback' => 'common_test_drupal_goto_land_fail',
+    'access arguments' => array('access content'),
+    'type' => MENU_CALLBACK,
+  );
+  $items['common-test/drupal_goto/redirect'] = array(
+    'title' => 'Drupal Goto',
+    'page callback' => 'common_test_drupal_goto_redirect',
+    'access arguments' => array('access content'),
+    'type' => MENU_CALLBACK,
+  );
+  $items['common-test/drupal_goto/redirect_advanced'] = array(
+    'title' => 'Drupal Goto',
+    'page callback' => 'common_test_drupal_goto_redirect_advanced',
+    'access arguments' => array('access content'),
+    'type' => MENU_CALLBACK,
+  );
+  $items['common-test/drupal_goto/redirect_fail'] = array(
+    'title' => 'Drupal Goto Failure',
+    'page callback' => 'drupal_goto',
+    'page arguments' => array('common-test/drupal_goto/fail'),
+    'access arguments' => array('access content'),
+    'type' => MENU_CALLBACK,
+  );
   $items['common-test/destination'] = array(
     'title' => 'Drupal Get Destination',
     'page callback' => 'common_test_destination',
@@ -31,6 +68,56 @@ function common_test_menu() {
 }
 
 /**
+ * Redirects using drupal_goto().
+ */
+function common_test_drupal_goto_redirect() {
+  drupal_goto('common-test/drupal_goto');
+}
+
+/**
+ * Redirects using drupal_goto().
+ */
+function common_test_drupal_goto_redirect_advanced() {
+  drupal_goto('common-test/drupal_goto', array('query' => array('foo' => '123')), 301);
+}
+
+/**
+ * Page callback: Provides a landing page for drupal_goto().
+ *
+ * @see common_test_menu()
+ */
+function common_test_drupal_goto_land() {
+  print "drupal_goto";
+}
+
+/**
+ * Page callback: Provides a landing page for drupal_goto().
+ *
+ * @see common_test_menu()
+ */
+function common_test_drupal_goto_land_alternative() {
+  print "drupal_goto_alternative";
+}
+
+/**
+ * Page callback: Provides a failure landing page for drupal_goto().
+ *
+ * @see common_test_menu()
+ */
+function common_test_drupal_goto_land_fail() {
+  print "drupal_goto_fail";
+}
+
+/**
+ * Implements hook_drupal_goto_alter().
+ */
+function common_test_drupal_goto_alter(&$path, &$options, &$http_response_code) {
+  if ($path == 'common-test/drupal_goto/fail') {
+    $path = 'common-test/drupal_goto/redirect';
+  }
+}
+
+/**
  * Prints a destination query parameter.
  */
 function common_test_destination() {
diff --git a/core/modules/system/tests/modules/form_test/form_test.module b/core/modules/system/tests/modules/form_test/form_test.module
index 25ae931..9c36916 100644
--- a/core/modules/system/tests/modules/form_test/form_test.module
+++ b/core/modules/system/tests/modules/form_test/form_test.module
@@ -387,7 +387,6 @@ function _form_test_submit_values_json($form, &$form_state) {
   $response = new JsonResponse($form_state['values']);
   // @todo remove once converted to new routing system.
   $response->send();
-  exit;
 }
 
 /**
diff --git a/core/modules/system/tests/modules/session_test/lib/Drupal/session_test/EventSubscriber/SessionTestSubscriber.php b/core/modules/system/tests/modules/session_test/lib/Drupal/session_test/EventSubscriber/SessionTestSubscriber.php
index 45234a8..c9f1b0a 100644
--- a/core/modules/system/tests/modules/session_test/lib/Drupal/session_test/EventSubscriber/SessionTestSubscriber.php
+++ b/core/modules/system/tests/modules/session_test/lib/Drupal/session_test/EventSubscriber/SessionTestSubscriber.php
@@ -7,11 +7,10 @@
 
 namespace Drupal\session_test\EventSubscriber;
 
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-use Symfony\Component\HttpFoundation\RedirectResponse;
 use Symfony\Component\HttpKernel\KernelEvents;
 use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
 use Symfony\Component\HttpKernel\Event\GetResponseEvent;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
 
 /**
  * Defines a test session subscriber that checks whether the session is empty.
@@ -34,27 +33,13 @@ public function onKernelRequestSessionTest(GetResponseEvent $event) {
   }
 
   /**
-   * Performs tasks for session_test module on kernel.response.
+   * Set header for session testing.
    *
    * @param \Symfony\Component\HttpKernel\Event\FilterResponseEvent $event
    *   The Event to process.
    */
   public function onKernelResponseSessionTest(FilterResponseEvent $event) {
-    $response = $event->getResponse();
-    if ($response instanceOf RedirectResponse) {
-      // Force the redirection to go to a non-secure page after being on a
-      // secure page through https.php.
-      global $base_insecure_url, $is_https_mock;
-      // Alter the redirect to use HTTP when using a mock HTTPS request through
-      // https.php because form submissions would otherwise redirect to a
-      // non-existent HTTPS site.
-      if (!empty($is_https_mock)) {
-        $path = $base_insecure_url . '/' . $event->getTargetUrl();
-        $response->setTargetUrl($path);
-      }
-    }
-    // Set header for session testing.
-    $response->headers->set('X-Session-Empty', $this->emptySession);
+    $event->getResponse()->headers->set('X-Session-Empty', $this->emptySession);
   }
 
   /**
diff --git a/core/modules/system/tests/modules/session_test/session_test.module b/core/modules/system/tests/modules/session_test/session_test.module
index 73bf3ff..b3e82fd 100644
--- a/core/modules/system/tests/modules/session_test/session_test.module
+++ b/core/modules/system/tests/modules/session_test/session_test.module
@@ -162,6 +162,22 @@ function session_test_form_user_login_form_alter(&$form) {
 }
 
 /**
+ * Implements hook_drupal_goto_alter().
+ *
+ * Force the redirection to go to a non-secure page after being on a secure
+ * page through https.php.
+ */
+function session_test_drupal_goto_alter(&$path, &$options, &$http_response_code) {
+  global $base_insecure_url, $is_https_mock;
+  // Alter the redirect to use HTTP when using a mock HTTPS request through
+  // https.php because form submissions would otherwise redirect to a
+  // non-existent HTTPS site.
+  if (!empty($is_https_mock)) {
+    $path = $base_insecure_url . '/' . $path;
+  }
+}
+
+/**
  * Menu callback, only available if current user is logged in.
  */
 function _session_test_is_logged_in() {
diff --git a/core/modules/system/tests/modules/system_test/system_test.module b/core/modules/system/tests/modules/system_test/system_test.module
index ea10a04..b73bb5a 100644
--- a/core/modules/system/tests/modules/system_test/system_test.module
+++ b/core/modules/system/tests/modules/system_test/system_test.module
@@ -1,7 +1,5 @@
 <?php
 
-use Symfony\Component\HttpFoundation\RedirectResponse;
-
 /**
  * Implements hook_menu().
  */
@@ -278,5 +276,5 @@ function system_test_filetransfer_info() {
 function system_test_authorize_init_page($page_title) {
   $authorize_url = $GLOBALS['base_url'] . '/core/authorize.php';
   system_authorized_init('system_test_authorize_run', drupal_get_path('module', 'system_test') . '/system_test.module', array(), $page_title);
-  return new RedirectResponse($authorize_url);
+  drupal_goto($authorize_url);
 }
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Core/Entity/Vocabulary.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Core/Entity/Vocabulary.php
index 9d55435..c5a4aff 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Core/Entity/Vocabulary.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Core/Entity/Vocabulary.php
@@ -118,8 +118,8 @@ public function postSave(EntityStorageControllerInterface $storage_controller, $
       $fields = field_read_fields();
       foreach ($fields as $field_name => $field) {
         $update_field = FALSE;
-        if ($field['type'] == 'taxonomy_term_reference') {
-          foreach ($field['settings']['allowed_values'] as $key => &$value) {
+        if ($field->type == 'taxonomy_term_reference') {
+          foreach ($field->settings['allowed_values'] as $key => &$value) {
             if ($value['vocabulary'] == $this->getOriginalID()) {
               $value['vocabulary'] = $this->id();
               $update_field = TRUE;
@@ -159,14 +159,14 @@ public static function postDelete(EntityStorageControllerInterface $storage_cont
       $modified_field = FALSE;
       // Term reference fields may reference terms from more than one
       // vocabulary.
-      foreach ($taxonomy_field['settings']['allowed_values'] as $key => $allowed_value) {
+      foreach ($taxonomy_field->settings['allowed_values'] as $key => $allowed_value) {
         if (isset($vocabularies[$allowed_value['vocabulary']])) {
-          unset($taxonomy_field['settings']['allowed_values'][$key]);
+          unset($taxonomy_field->settings['allowed_values'][$key]);
           $modified_field = TRUE;
         }
       }
       if ($modified_field) {
-        if (empty($taxonomy_field['settings']['allowed_values'])) {
+        if (empty($taxonomy_field->settings['allowed_values'])) {
           $taxonomy_field->delete();
         }
         else {
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/entity_reference/selection/TermSelection.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/entity_reference/selection/TermSelection.php
index e49f31e..bccafdc 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/entity_reference/selection/TermSelection.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/entity_reference/selection/TermSelection.php
@@ -43,7 +43,7 @@ public static function settingsForm(&$field, &$instance) {
     $form['auto_create'] = array(
       '#type' => 'checkbox',
       '#title' => t("Create referenced entities if they don't already exist"),
-      '#default_value' => $instance['settings']['handler_settings']['auto_create'],
+      '#default_value' => $instance->settings['handler_settings']['auto_create'],
     );
     return $form;
 
@@ -61,7 +61,7 @@ public function getReferencableEntities($match = NULL, $match_operator = 'CONTAI
     $options = array();
 
     $bundles = entity_get_bundles('taxonomy_term');
-    $bundle_names = !empty($this->instance['settings']['handler_settings']['target_bundles']) ? $this->instance['settings']['handler_settings']['target_bundles'] : array_keys($bundles);
+    $bundle_names = !empty($this->instance->settings['handler_settings']['target_bundles']) ? $this->instance->settings['handler_settings']['target_bundles'] : array_keys($bundles);
 
     foreach ($bundle_names as $bundle) {
       if ($vocabulary = entity_load('taxonomy_vocabulary', $bundle)) {
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldMultipleVocabularyTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldMultipleVocabularyTest.php
index c19ce9d..9a3ce38 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldMultipleVocabularyTest.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldMultipleVocabularyTest.php
@@ -126,7 +126,7 @@ function testTaxonomyTermFieldMultipleVocabularies() {
 
     // Verify that field and instance settings are correct.
     $field_info = field_info_field($this->field_name);
-    $this->assertEqual(count($field_info['settings']['allowed_values']), 1, 'Only one vocabulary is allowed for the field.');
+    $this->assertEqual(count($field_info->settings['allowed_values']), 1, 'Only one vocabulary is allowed for the field.');
 
     // The widget should still be displayed.
     $this->drupalGet('entity_test/add');
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldTest.php
index 1db9e15..f8e82fd 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldTest.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldTest.php
@@ -171,7 +171,7 @@ function testTaxonomyTermFieldChangeMachineName() {
 
     // Check that the field instance is still attached to the vocabulary.
     $field = field_info_field($this->field_name);
-    $allowed_values = $field['settings']['allowed_values'];
+    $allowed_values = $field->settings['allowed_values'];
     $this->assertEqual($allowed_values[0]['vocabulary'], $new_name, 'Index 0: Machine name was updated correctly.');
     $this->assertEqual($allowed_values[1]['vocabulary'], $new_name, 'Index 1: Machine name was updated correctly.');
     $this->assertEqual($allowed_values[2]['vocabulary'], 'foo', 'Index 2: Machine name was left untouched.');
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermTest.php
index caf5397..11aff45 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermTest.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermTest.php
@@ -55,7 +55,7 @@ function setUp() {
       ))
       ->save();
     entity_get_display('node', 'article', 'default')
-      ->setComponent($this->instance['field_name'], array(
+      ->setComponent($this->instance->getFieldName(), array(
         'type' => 'taxonomy_term_reference_link',
       ))
       ->save();
@@ -113,7 +113,7 @@ function testTaxonomyNode() {
     $langcode = Language::LANGCODE_NOT_SPECIFIED;
     $edit["title"] = $this->randomName();
     $edit["body[$langcode][0][value]"] = $this->randomName();
-    $edit[$this->instance['field_name'] . '[' . $langcode . '][]'] = $term1->id();
+    $edit[$this->instance->getFieldName() . '[' . $langcode . '][]'] = $term1->id();
     $this->drupalPost('node/add/article', $edit, t('Save'));
 
     // Check that the term is displayed when the node is viewed.
@@ -127,7 +127,7 @@ function testTaxonomyNode() {
     $this->assertText($term1->label(), 'Term is displayed after saving the node with no changes.');
 
     // Edit the node with a different term.
-    $edit[$this->instance['field_name'] . '[' . $langcode . '][]'] = $term2->id();
+    $edit[$this->instance->getFieldName() . '[' . $langcode . '][]'] = $term2->id();
     $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
 
     $this->drupalGet('node/' . $node->nid);
@@ -146,8 +146,8 @@ function testTaxonomyNode() {
   function testNodeTermCreationAndDeletion() {
     // Enable tags in the vocabulary.
     $instance = $this->instance;
-    entity_get_form_display($instance['entity_type'], $instance['bundle'], 'default')
-      ->setComponent($instance['field_name'], array(
+    entity_get_form_display($instance->entity_type, $instance->bundle, 'default')
+      ->setComponent($instance->getFieldName(), array(
         'type' => 'taxonomy_autocomplete',
         'settings' => array(
           'placeholder' => 'Start typing here.',
@@ -167,7 +167,7 @@ function testNodeTermCreationAndDeletion() {
     $edit["body[$langcode][0][value]"] = $this->randomName();
     // Insert the terms in a comma separated list. Vocabulary 1 is a
     // free-tagging field created by the default profile.
-    $edit[$instance['field_name'] . "[$langcode]"] = drupal_implode_tags($terms);
+    $edit[$instance->getFieldName() . "[$langcode]"] = drupal_implode_tags($terms);
 
     // Verify the placeholder is there.
     $this->drupalGet('node/add/article');
@@ -515,8 +515,8 @@ function testTaxonomyGetTermByName() {
   function testReSavingTags() {
     // Enable tags in the vocabulary.
     $instance = $this->instance;
-    entity_get_form_display($instance['entity_type'], $instance['bundle'], 'default')
-      ->setComponent($instance['field_name'], array(
+    entity_get_form_display($instance->entity_type, $instance->bundle, 'default')
+      ->setComponent($instance->getFieldName(), array(
         'type' => 'taxonomy_autocomplete',
       ))
       ->save();
@@ -527,7 +527,7 @@ function testReSavingTags() {
     $edit = array();
     $edit["title"] = $this->randomName(8);
     $edit["body[$langcode][0][value]"] = $this->randomName(16);
-    $edit[$this->instance['field_name'] . '[' . $langcode . ']'] = $term->label();
+    $edit[$this->instance->getFieldName() . '[' . $langcode . ']'] = $term->label();
     $this->drupalPost('node/add/article', $edit, t('Save'));
 
     // Check that the term is displayed when editing and saving the node with no
diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module
index 980ad00..616295b 100644
--- a/core/modules/taxonomy/taxonomy.module
+++ b/core/modules/taxonomy/taxonomy.module
@@ -961,7 +961,7 @@ function taxonomy_field_validate(EntityInterface $entity = NULL, $field, $instan
       $validate = TRUE;
       if (!empty($item['tid']) && $item['tid'] != 'autocreate') {
         $validate = FALSE;
-        foreach ($field['settings']['allowed_values'] as $settings) {
+        foreach ($field->settings['allowed_values'] as $settings) {
           // If no parent is specified, check if the term is in the vocabulary.
           if (isset($settings['vocabulary']) && empty($settings['parent'])) {
             if ($settings['vocabulary'] == $terms[$item['tid']]->bundle()) {
@@ -983,9 +983,9 @@ function taxonomy_field_validate(EntityInterface $entity = NULL, $field, $instan
         }
       }
       if (!$validate) {
-        $errors[$field['field_name']][$langcode][$delta][] = array(
+        $errors[$field->id()][$langcode][$delta][] = array(
           'error' => 'taxonomy_term_reference_illegal_value',
-          'message' => t('%name: illegal value.', array('%name' => $instance['label'])),
+          'message' => t('%name: illegal value.', array('%name' => $instance->label())),
         );
       }
     }
@@ -1064,7 +1064,7 @@ function taxonomy_field_settings_form($field, $instance) {
     '#tree' => TRUE,
   );
 
-  foreach ($field['settings']['allowed_values'] as $delta => $tree) {
+  foreach ($field->settings['allowed_values'] as $delta => $tree) {
     $form['allowed_values'][$delta]['vocabulary'] = array(
       '#type' => 'select',
       '#title' => t('Vocabulary'),
@@ -1199,9 +1199,9 @@ function taxonomy_build_node_index($node) {
     // Collect a unique list of all the term IDs from all node fields.
     $tid_all = array();
     foreach (field_info_instances('node', $node->type) as $instance) {
-      $field_name = $instance['field_name'];
+      $field_name = $instance->getFieldName();
       $field = field_info_field($field_name);
-      if ($field['module'] == 'taxonomy' && $field['storage']['type'] == 'field_sql_storage') {
+      if ($field->module == 'taxonomy' && $field->storage['type'] == 'field_sql_storage') {
         // If a field value is not set in the node object when $node->save() is
         // called, the old value from $node->original is used.
         if (isset($node->{$field_name})) {
diff --git a/core/modules/taxonomy/taxonomy.pages.inc b/core/modules/taxonomy/taxonomy.pages.inc
index d70b8fd..593c620 100644
--- a/core/modules/taxonomy/taxonomy.pages.inc
+++ b/core/modules/taxonomy/taxonomy.pages.inc
@@ -110,7 +110,7 @@ function taxonomy_autocomplete($field_name) {
   $tags_typed = Drupal::request()->query->get('q');
 
   // Make sure the field exists and is a taxonomy field.
-  if (!($field = field_info_field($field_name)) || $field['type'] !== 'taxonomy_term_reference') {
+  if (!($field = field_info_field($field_name)) || $field->type !== 'taxonomy_term_reference') {
     // Error string. The JavaScript handler will realize this is not JSON and
     // will display it as debugging information.
     print t('Taxonomy field @field_name not found.', array('@field_name' => $field_name));
@@ -126,7 +126,7 @@ function taxonomy_autocomplete($field_name) {
 
     // Part of the criteria for the query come from the field's own settings.
     $vids = array();
-    foreach ($field['settings']['allowed_values'] as $tree) {
+    foreach ($field->settings['allowed_values'] as $tree) {
       $vids[] = $tree['vocabulary'];
     }
 
diff --git a/core/modules/taxonomy/taxonomy.views.inc b/core/modules/taxonomy/taxonomy.views.inc
index d52819b..faa5087 100644
--- a/core/modules/taxonomy/taxonomy.views.inc
+++ b/core/modules/taxonomy/taxonomy.views.inc
@@ -341,16 +341,16 @@ function taxonomy_field_views_data($field) {
     foreach ($table_data as $field_name => $field_data) {
       if (isset($field_data['filter']) && $field_name != 'delta') {
         $data[$table_name][$field_name]['filter']['id'] = 'taxonomy_index_tid';
-        $data[$table_name][$field_name]['filter']['vocabulary'] = $field['settings']['allowed_values'][0]['vocabulary'];
+        $data[$table_name][$field_name]['filter']['vocabulary'] = $field->settings['allowed_values'][0]['vocabulary'];
       }
     }
 
     // Add the relationship only on the tid field.
-    $data[$table_name][$field['field_name'] . '_tid']['relationship'] = array(
+    $data[$table_name][$field->id() . '_tid']['relationship'] = array(
       'id' => 'standard',
       'base' => 'taxonomy_term_data',
       'base field' => 'tid',
-      'label' => t('term from !field_name', array('!field_name' => $field['field_name'])),
+      'label' => t('term from !field_name', array('!field_name' => $field->id())),
     );
 
   }
@@ -364,11 +364,11 @@ function taxonomy_field_views_data($field) {
  * Views integration to provide reverse relationships on term references.
  */
 function taxonomy_field_views_data_views_data_alter(&$data, $field) {
-  foreach ($field['bundles'] as $entity_type => $bundles) {
+  foreach ($field->getBundles() as $entity_type => $bundles) {
     $entity_info = entity_get_info($entity_type);
-    $pseudo_field_name = 'reverse_' . $field['field_name'] . '_' . $entity_type;
+    $pseudo_field_name = 'reverse_' . $field->id() . '_' . $entity_type;
 
-    list($label, $all_labels) = field_views_field_label($field['field_name']);
+    list($label, $all_labels) = field_views_field_label($field->id());
     $entity = $entity_info['label'];
     if ($entity == t('Node')) {
       $entity = t('Content');
@@ -378,12 +378,12 @@ function taxonomy_field_views_data_views_data_alter(&$data, $field) {
       'title' => t('@entity using @field', array('@entity' => $entity, '@field' => $label)),
       'help' => t('Relate each @entity with a @field set to the term.', array('@entity' => $entity, '@field' => $label)),
       'id' => 'entity_reverse',
-      'field_name' => $field['field_name'],
+      'field_name' => $field->id(),
       'field table' => _field_sql_storage_tablename($field),
-      'field field' => $field['field_name'] . '_tid',
+      'field field' => $field->id() . '_tid',
       'base' => $entity_info['base_table'],
       'base field' => $entity_info['entity_keys']['id'],
-      'label' => t('!field_name', array('!field_name' => $field['field_name'])),
+      'label' => t('!field_name', array('!field_name' => $field->id())),
       'join_extra' => array(
         0 => array(
           'field' => 'entity_type',
diff --git a/core/modules/text/lib/Drupal/text/TextProcessed.php b/core/modules/text/lib/Drupal/text/TextProcessed.php
index 6e8cb83..ed307bf 100644
--- a/core/modules/text/lib/Drupal/text/TextProcessed.php
+++ b/core/modules/text/lib/Drupal/text/TextProcessed.php
@@ -69,7 +69,7 @@ public function getValue($langcode = NULL) {
     $entity = $field->getParent();
     $instance = field_info_instance($entity->entityType(), $field->getName(), $entity->bundle());
 
-    if (!empty($instance['settings']['text_processing']) && $this->format->getValue()) {
+    if (!empty($instance->settings['text_processing']) && $this->format->getValue()) {
       return check_markup($this->text->getValue(), $this->format->getValue(), $entity->language()->langcode);
     }
     else {
diff --git a/core/modules/text/text.install b/core/modules/text/text.install
index 72d879f..d87d7f7 100644
--- a/core/modules/text/text.install
+++ b/core/modules/text/text.install
@@ -9,12 +9,12 @@
  * Implements hook_field_schema().
  */
 function text_field_schema($field) {
-  switch ($field['type']) {
+  switch ($field->type) {
     case 'text':
       $columns = array(
         'value' => array(
           'type' => 'varchar',
-          'length' => $field['settings']['max_length'],
+          'length' => $field->settings['max_length'],
           'not null' => FALSE,
         ),
       );
diff --git a/core/modules/text/text.module b/core/modules/text/text.module
index 4bc0f30..205a524 100644
--- a/core/modules/text/text.module
+++ b/core/modules/text/text.module
@@ -85,11 +85,11 @@ function text_field_info() {
  * Implements hook_field_settings_form().
  */
 function text_field_settings_form($field, $instance) {
-  $settings = $field['settings'];
+  $settings = $field->settings;
 
   $form = array();
 
-  if ($field['type'] == 'text') {
+  if ($field->type == 'text') {
     $form['max_length'] = array(
       '#type' => 'number',
       '#title' => t('Maximum length'),
@@ -110,7 +110,7 @@ function text_field_settings_form($field, $instance) {
  * Implements hook_field_instance_settings_form().
  */
 function text_field_instance_settings_form($field, $instance) {
-  $settings = $instance['settings'];
+  $settings = $instance->settings;
 
   $form['text_processing'] = array(
     '#type' => 'radios',
@@ -121,7 +121,7 @@ function text_field_instance_settings_form($field, $instance) {
       t('Filtered text (user selects text format)'),
     ),
   );
-  if ($field['type'] == 'text_with_summary') {
+  if ($field->type == 'text_with_summary') {
     $form['display_summary'] = array(
       '#type' => 'checkbox',
       '#title' => t('Summary input'),
@@ -146,17 +146,17 @@ function text_field_validate(EntityInterface $entity = NULL, $field, $instance,
     //   length can be exceeded very easily.
     foreach (array('value', 'summary') as $column) {
       if (!empty($item[$column])) {
-        if (!empty($field['settings']['max_length']) && drupal_strlen($item[$column]) > $field['settings']['max_length']) {
+        if (!empty($field->settings['max_length']) && drupal_strlen($item[$column]) > $field->settings['max_length']) {
           switch ($column) {
             case 'value':
-              $message = t('%name: the text may not be longer than %max characters.', array('%name' => $instance['label'], '%max' => $field['settings']['max_length']));
+              $message = t('%name: the text may not be longer than %max characters.', array('%name' => $instance->label(), '%max' => $field->settings['max_length']));
               break;
 
             case 'summary':
-              $message = t('%name: the summary may not be longer than %max characters.', array('%name' => $instance['label'], '%max' => $field['settings']['max_length']));
+              $message = t('%name: the summary may not be longer than %max characters.', array('%name' => $instance->label(), '%max' => $field->settings['max_length']));
               break;
           }
-          $errors[$field['field_name']][$langcode][$delta][] = array(
+          $errors[$field->id()][$langcode][$delta][] = array(
             'error' => "text_{$column}_length",
             'message' => $message,
           );
@@ -178,10 +178,10 @@ function text_field_load($entity_type, $entities, $field, $instances, $langcode,
     foreach ($items[$id] as $delta => $item) {
       // Only process items with a cacheable format, the rest will be handled
       // by formatters if needed.
-      if (empty($instances[$id]['settings']['text_processing']) || filter_format_allowcache($item['format'])) {
-        $items[$id][$delta]['safe_value'] = isset($item['value']) ? text_sanitize($instances[$id]['settings']['text_processing'], $langcode, $item, 'value') : '';
-        if ($field['type'] == 'text_with_summary') {
-          $items[$id][$delta]['safe_summary'] = isset($item['summary']) ? text_sanitize($instances[$id]['settings']['text_processing'], $langcode, $item, 'summary') : '';
+      if (empty($instances[$id]->settings['text_processing']) || filter_format_allowcache($item['format'])) {
+        $items[$id][$delta]['safe_value'] = isset($item['value']) ? text_sanitize($instances[$id]->settings['text_processing'], $langcode, $item, 'value') : '';
+        if ($field->type == 'text_with_summary') {
+          $items[$id][$delta]['safe_summary'] = isset($item['summary']) ? text_sanitize($instances[$id]->settings['text_processing'], $langcode, $item, 'summary') : '';
         }
       }
     }
@@ -365,7 +365,7 @@ function text_summary($text, $format = NULL, $size = NULL) {
 function text_field_prepare_translation(EntityInterface $entity, $field, $instance, $langcode, &$items, EntityInterface $source_entity, $source_langcode) {
   // If the translating user is not permitted to use the assigned text format,
   // we must not expose the source values.
-  $field_name = $field['field_name'];
+  $field_name = $field->id();
   if (!empty($source_entity->{$field_name}[$source_langcode])) {
     $formats = filter_formats();
     foreach ($source_entity->{$field_name}[$source_langcode] as $delta => $item) {
diff --git a/core/modules/translation_entity/lib/Drupal/translation_entity/EntityTranslationController.php b/core/modules/translation_entity/lib/Drupal/translation_entity/EntityTranslationController.php
index 1fb68e5..fba7d3f 100644
--- a/core/modules/translation_entity/lib/Drupal/translation_entity/EntityTranslationController.php
+++ b/core/modules/translation_entity/lib/Drupal/translation_entity/EntityTranslationController.php
@@ -50,9 +50,9 @@ public function removeTranslation(EntityInterface $entity, $langcode) {
     // @todo Handle properties.
     // Remove field translations.
     foreach (field_info_instances($entity->entityType(), $entity->bundle()) as $instance) {
-      $field_name = $instance['field_name'];
+      $field_name = $instance->getFieldName();
       $field = field_info_field($field_name);
-      if ($field['translatable']) {
+      if ($field->translatable) {
         $entity->{$field_name}[$langcode] = array();
       }
     }
@@ -469,7 +469,7 @@ public function entityFormSourceChange($form, &$form_state) {
     $entity = $form_controller->getEntity();
     $source = $form_state['values']['source_langcode']['source'];
     $path = $this->getBasePath($entity) . '/translations/add/' . $source . '/' . $form_controller->getFormLangcode($form_state);
-    $form_state['redirect'] = $path;
+    $form_state['redirect'] = array('path' => $path);
     $languages = language_list();
     drupal_set_message(t('Source language set to: %language', array('%language' => $languages[$source]->name)));
   }
diff --git a/core/modules/translation_entity/lib/Drupal/translation_entity/FieldTranslationSynchronizer.php b/core/modules/translation_entity/lib/Drupal/translation_entity/FieldTranslationSynchronizer.php
index 39d1a21..8d2016b 100644
--- a/core/modules/translation_entity/lib/Drupal/translation_entity/FieldTranslationSynchronizer.php
+++ b/core/modules/translation_entity/lib/Drupal/translation_entity/FieldTranslationSynchronizer.php
@@ -66,14 +66,14 @@ public function synchronizeFields(EntityInterface $entity, $sync_langcode, $orig
 
       // Sync when the field is not empty, when the synchronization translations
       // setting is set, and the field is translatable.
-      if (!$entity->get($field_name)->isEmpty() && !empty($instance['settings']['translation_sync']) && field_is_translatable($entity_type, $field)) {
+      if (!$entity->get($field_name)->isEmpty() && !empty($instance->settings['translation_sync']) && field_is_translatable($entity_type, $field)) {
         // Retrieve all the untranslatable column groups and merge them into
         // single list.
-        $groups = array_keys(array_diff($instance['settings']['translation_sync'], array_filter($instance['settings']['translation_sync'])));
+        $groups = array_keys(array_diff($instance->settings['translation_sync'], array_filter($instance->settings['translation_sync'])));
         if (!empty($groups)) {
           $columns = array();
           foreach ($groups as $group) {
-            $info = $field['settings']['column_groups'][$group];
+            $info = $field->settings['column_groups'][$group];
             // A missing 'columns' key indicates we have a single-column group.
             $columns = array_merge($columns, isset($info['columns']) ? $info['columns'] : array($group));
           }
diff --git a/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationSettingsTest.php b/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationSettingsTest.php
index cb90b6d..83b4b37 100644
--- a/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationSettingsTest.php
+++ b/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationSettingsTest.php
@@ -90,7 +90,7 @@ function testSettingsUI() {
     $this->assertSettings('comment', 'comment_node_article', TRUE, $edit);
     field_info_cache_clear();
     $field = field_info_field('comment_body');
-    $this->assertTrue($field['translatable'], 'Comment body is translatable.');
+    $this->assertTrue($field->translatable, 'Comment body is translatable.');
 
     // Test that language settings are correctly stored.
     $language_configuration = language_get_default_configuration('comment', 'comment_node_article');
diff --git a/core/modules/translation_entity/translation_entity.admin.inc b/core/modules/translation_entity/translation_entity.admin.inc
index 01e9368..bb342bd 100644
--- a/core/modules/translation_entity/translation_entity.admin.inc
+++ b/core/modules/translation_entity/translation_entity.admin.inc
@@ -24,11 +24,11 @@
 function translation_entity_field_sync_widget(Field $field, FieldInstance $instance) {
   $element = array();
 
-  if (!empty($field['settings']['column_groups']) && count($field['settings']['column_groups']) > 1) {
+  if (!empty($field->settings['column_groups']) && count($field->settings['column_groups']) > 1) {
     $options = array();
     $default = array();
 
-    foreach ($field['settings']['column_groups'] as $group => $info) {
+    foreach ($field->settings['column_groups'] as $group => $info) {
       $options[$group] = $info['label'];
       $default[$group] = !empty($info['translatable']) ? $group : FALSE;
     }
@@ -39,7 +39,7 @@ function translation_entity_field_sync_widget(Field $field, FieldInstance $insta
       '#type' => 'checkboxes',
       '#title' => t('Translatable elements'),
       '#options' => $options,
-      '#default_value' => !empty($instance['settings']['translation_sync']) ? $instance['settings']['translation_sync'] : $default,
+      '#default_value' => !empty($instance->settings['translation_sync']) ? $instance->settings['translation_sync'] : $default,
       '#attached' => array(
         'library' => array(
           array('translation_entity', 'drupal.translation_entity.admin'),
@@ -97,9 +97,9 @@ function _translation_entity_form_language_content_settings_form_alter(array &$f
           foreach ($fields as $field_name => $instance) {
             $field = field_info_field($field_name);
             $form['settings'][$entity_type][$bundle]['fields'][$field_name] = array(
-              '#label' => $instance['label'],
+              '#label' => $instance->label(),
               '#type' => 'checkbox',
-              '#default_value' => $field['translatable'],
+              '#default_value' => $field->translatable,
             );
             $column_element = translation_entity_field_sync_widget($field, $instance);
             if ($column_element) {
@@ -337,7 +337,7 @@ function _translation_entity_update_field_translatability($settings) {
   $operations = array();
   foreach ($fields as $field_name => $translatable) {
     $field = field_info_field($field_name);
-    if ($field['translatable'] != $translatable) {
+    if ($field->translatable != $translatable) {
       // If a field is untranslatable, it can have no data except under
       // Language::LANGCODE_NOT_SPECIFIED. Thus we need a field to be translatable before
       // we convert data to the entity language. Conversely we need to switch
@@ -374,7 +374,7 @@ function translation_entity_translatable_form(array $form, array &$form_state, $
   $t_args = array('%name' => $field_name);
 
   $warning = t('By submitting this form these changes will apply to the %name field everywhere it is used.', $t_args);
-  if ($field['translatable']) {
+  if ($field->translatable) {
     $title = t('Are you sure you want to disable translation for the %name field?', $t_args);
     $warning .= "<br>" . t("<strong>All the existing translations of this field will be deleted.</strong><br>This action cannot be undone.");
   }
@@ -389,7 +389,7 @@ function translation_entity_translatable_form(array $form, array &$form_state, $
   // submits from toggling translatability.
   $form['translatable'] = array(
     '#type' => 'hidden',
-    '#default_value' => $field['translatable'],
+    '#default_value' => $field->translatable,
   );
 
   return confirm_form($form, $title, '', $warning);
@@ -413,7 +413,7 @@ function translation_entity_translatable_form_submit(array $form, array $form_st
   $field_name = $form_state['field']['field_name'];
   $field = field_info_field($field_name);
 
-  if ($field['translatable'] !== $translatable) {
+  if ($field->translatable !== $translatable) {
     // Field translatability has changed since form creation, abort.
     $t_args = array('%field_name');
     $msg = $translatable ?
@@ -460,8 +460,8 @@ function translation_entity_translatable_form_submit(array $form, array $form_st
  */
 function translation_entity_translatable_switch($translatable, $field_name) {
   $field = field_info_field($field_name);
-  if ($field['translatable'] !== $translatable) {
-    $field['translatable'] = $translatable;
+  if ($field->translatable !== $translatable) {
+    $field->translatable = $translatable;
     $field->save();
   }
 }
@@ -477,7 +477,8 @@ function translation_entity_translatable_switch($translatable, $field_name) {
  */
 function translation_entity_translatable_batch($translatable, $field_name, &$context) {
   $field = field_info_field($field_name);
-  $column = isset($field['columns']['value']) ? 'value' : key($field['columns']);
+  $columns = $field->getSchema('columns');
+  $column = isset($columns['value']) ? 'value' : key($columns);
   $query_field = "$field_name.$column";
 
   // Determine the entity types to act on.
diff --git a/core/modules/translation_entity/translation_entity.module b/core/modules/translation_entity/translation_entity.module
index dec0460..5f97c47 100644
--- a/core/modules/translation_entity/translation_entity.module
+++ b/core/modules/translation_entity/translation_entity.module
@@ -622,9 +622,9 @@ function translation_entity_form_alter(array &$form, array &$form_state) {
       }
       else {
         foreach (field_info_instances($entity->entityType(), $entity->bundle()) as $instance) {
-          $field_name = $instance['field_name'];
+          $field_name = $instance->getFieldName();
           $field = field_info_field($field_name);
-          $form[$field_name]['#multilingual'] = !empty($field['translatable']);
+          $form[$field_name]['#multilingual'] = !empty($field->translatable);
         }
       }
     }
@@ -657,9 +657,9 @@ function translation_entity_field_language_alter(&$display_language, $context) {
           //   entity language and with Language::LANGCODE_DEFAULT. We need need to unset
           //   both until we remove the BC layer.
           if ($langcode == $entity_langcode) {
-            unset($entity->{$instance['field_name']}[Language::LANGCODE_DEFAULT]);
+            unset($entity->{$instance->getFieldName()}[Language::LANGCODE_DEFAULT]);
           }
-          unset($entity->{$instance['field_name']}[$langcode]);
+          unset($entity->{$instance->getFieldName()}[$langcode]);
         }
       }
     }
@@ -806,8 +806,8 @@ function translation_entity_field_extra_fields() {
  */
 function translation_entity_form_field_ui_field_edit_form_alter(array &$form, array &$form_state, $form_id) {
   $field = $form['#field'];
-  $field_name = $field['field_name'];
-  $translatable = $field['translatable'];
+  $field_name = $field->id();
+  $translatable = $field->translatable;
   $label = t('Field translation');
 
   if ($field->hasData()) {
@@ -1020,13 +1020,13 @@ function translation_entity_save_settings($settings) {
           foreach ($bundle_settings['columns'] as $field_name => $column_settings) {
             $field = field_info_field($field_name);
             $instance = field_info_instance($entity_type, $field_name, $bundle);
-            if ($field['translatable']) {
-              $instance['settings']['translation_sync'] = $column_settings;
+            if ($field->translatable) {
+              $instance->settings['translation_sync'] = $column_settings;
             }
             // If the field does not have translatable enabled we need to reset
             // the sync settings to their defaults.
             else {
-              unset($instance['settings']['translation_sync']);
+              unset($instance->settings['translation_sync']);
             }
             $instance->save();
           }
diff --git a/core/modules/translation_entity/translation_entity.pages.inc b/core/modules/translation_entity/translation_entity.pages.inc
index cd212eb..0586b20 100644
--- a/core/modules/translation_entity/translation_entity.pages.inc
+++ b/core/modules/translation_entity/translation_entity.pages.inc
@@ -40,9 +40,9 @@ function translation_entity_overview(EntityInterface $entity) {
     // Determine whether the current entity is translatable.
     $translatable = FALSE;
     foreach (field_info_instances($entity->entityType(), $entity->bundle()) as $instance) {
-      $field_name = $instance['field_name'];
+      $field_name = $instance->getFieldName();
       $field = field_info_field($field_name);
-      if ($field['translatable']) {
+      if ($field->translatable) {
         $translatable = TRUE;
         break;
       }
@@ -253,7 +253,7 @@ function translation_entity_prepare_translation(EntityInterface $entity, Languag
   else {
     foreach ($instances as $field_name => $instance) {
       $field = field_info_field($field_name);
-      if (!empty($field['translatable'])) {
+      if (!empty($field->translatable)) {
         $value = $entity->get($field_name);
         $value[$target->langcode] = isset($value[$source->langcode]) ? $value[$source->langcode] : array();
         $entity->set($field_name, $value);
diff --git a/core/modules/update/update.authorize.inc b/core/modules/update/update.authorize.inc
index 57acc34..c74a93f 100644
--- a/core/modules/update/update.authorize.inc
+++ b/core/modules/update/update.authorize.inc
@@ -53,7 +53,7 @@ function update_authorize_run_update($filetransfer, $projects) {
 
   batch_set($batch);
   // Invoke the batch via authorize.php.
-  return system_authorized_batch_process();
+  system_authorized_batch_process();
 }
 
 /**
@@ -98,7 +98,7 @@ function update_authorize_run_install($filetransfer, $project, $updater_name, $l
   batch_set($batch);
 
   // Invoke the batch via authorize.php.
-  return system_authorized_batch_process();
+  system_authorized_batch_process();
 }
 
 /**
diff --git a/core/modules/update/update.fetch.inc b/core/modules/update/update.fetch.inc
index 13a1383..57283ea 100644
--- a/core/modules/update/update.fetch.inc
+++ b/core/modules/update/update.fetch.inc
@@ -28,7 +28,7 @@ function update_manual_status() {
     'file' => drupal_get_path('module', 'update') . '/update.fetch.inc',
   );
   batch_set($batch);
-  return batch_process('admin/reports/updates');
+  batch_process('admin/reports/updates');
 }
 
 /**
diff --git a/core/modules/update/update.manager.inc b/core/modules/update/update.manager.inc
index 8e2bce9..bc73db0 100644
--- a/core/modules/update/update.manager.inc
+++ b/core/modules/update/update.manager.inc
@@ -38,7 +38,6 @@
 
 use Drupal\Core\Updater\Updater;
 use Drupal\Core\FileTransfer\Local;
-use Symfony\Component\HttpFoundation\RedirectResponse;
 
 /**
  * @defgroup update_manager_update Update Manager module: update
@@ -357,7 +356,7 @@ function update_manager_download_batch_finished($success, $results) {
   elseif ($success) {
     drupal_set_message(t('Updates downloaded successfully.'));
     $_SESSION['update_manager_update_projects'] = $results['projects'];
-    return new RedirectResponse(url('admin/update/ready', array('absolute' => TRUE)));
+    drupal_goto('admin/update/ready');
   }
   else {
     // Ideally we're catching all Exceptions, so they should never see this,
diff --git a/core/modules/user/lib/Drupal/user/Controller/UserController.php b/core/modules/user/lib/Drupal/user/Controller/UserController.php
index e782019..864e095 100644
--- a/core/modules/user/lib/Drupal/user/Controller/UserController.php
+++ b/core/modules/user/lib/Drupal/user/Controller/UserController.php
@@ -41,7 +41,9 @@ public static function create(ContainerInterface $container) {
    */
   public function logout(Request $request) {
     user_logout();
-    return new RedirectResponse(url('<front>', array('absolute' => TRUE)));
+    // @todo Remove the destination check once drupal.org/node/1668866 is in.
+    $url = $request->query->get('destination') ?: '<front>';
+    return new RedirectResponse(url($url, array('absolute' => TRUE)));
   }
 
 }
diff --git a/core/modules/user/lib/Drupal/user/Plugin/entity_reference/selection/UserSelection.php b/core/modules/user/lib/Drupal/user/Plugin/entity_reference/selection/UserSelection.php
index 49f00a5..ee7fb6a 100644
--- a/core/modules/user/lib/Drupal/user/Plugin/entity_reference/selection/UserSelection.php
+++ b/core/modules/user/lib/Drupal/user/Plugin/entity_reference/selection/UserSelection.php
@@ -32,7 +32,7 @@ class UserSelection extends SelectionBase {
    */
   public static function settingsForm(&$field, &$instance) {
     // Merge in default values.
-    $instance['settings']['handler_settings'] += array(
+    $instance->settings['handler_settings'] += array(
       'filter' => array(
         'type' => '_none',
       ),
@@ -48,7 +48,7 @@ public static function settingsForm(&$field, &$instance) {
       ),
       '#ajax' => TRUE,
       '#limit_validation_errors' => array(),
-      '#default_value' => $instance['settings']['handler_settings']['filter']['type'],
+      '#default_value' => $instance->settings['handler_settings']['filter']['type'],
     );
 
     $form['filter']['settings'] = array(
@@ -57,9 +57,9 @@ public static function settingsForm(&$field, &$instance) {
       '#process' => array('_entity_reference_form_process_merge_parent'),
     );
 
-    if ($instance['settings']['handler_settings']['filter']['type'] == 'role') {
+    if ($instance->settings['handler_settings']['filter']['type'] == 'role') {
       // Merge in default values.
-      $instance['settings']['handler_settings']['filter'] += array(
+      $instance->settings['handler_settings']['filter'] += array(
         'role' => NULL,
       );
 
@@ -68,7 +68,7 @@ public static function settingsForm(&$field, &$instance) {
         '#title' => t('Restrict to the selected roles'),
         '#required' => TRUE,
         '#options' => array_diff_key(user_role_names(TRUE), drupal_map_assoc(array(DRUPAL_AUTHENTICATED_RID))),
-        '#default_value' => $instance['settings']['handler_settings']['filter']['role'],
+        '#default_value' => $instance->settings['handler_settings']['filter']['role'],
       );
     }
 
@@ -133,8 +133,8 @@ public function entityQueryAlter(SelectInterface $query) {
     }
 
     // Add the filter by role option.
-    if (!empty($this->instance['settings']['handler_settings']['filter'])) {
-      $filter_settings = $this->instance['settings']['handler_settings']['filter'];
+    if (!empty($this->instance->settings['handler_settings']['filter'])) {
+      $filter_settings = $this->instance->settings['handler_settings']['filter'];
       if ($filter_settings['type'] == 'role') {
         $tables = $query->getTables();
         $base_table = $tables['base_table']['alias'];
diff --git a/core/modules/user/lib/Drupal/user/RegisterFormController.php b/core/modules/user/lib/Drupal/user/RegisterFormController.php
index 7d22cd3..2acf0a6 100644
--- a/core/modules/user/lib/Drupal/user/RegisterFormController.php
+++ b/core/modules/user/lib/Drupal/user/RegisterFormController.php
@@ -7,8 +7,6 @@
 
 namespace Drupal\user;
 
-use Symfony\Component\HttpFoundation\RedirectResponse;
-
 /**
  * Form controller for the user register forms.
  */
@@ -33,7 +31,7 @@ public function form(array $form, array &$form_state) {
 
     // If we aren't admin but already logged on, go to the user page instead.
     if (!$admin && $user->uid) {
-      return new RedirectResponse(url('user/' . $user->uid, array('absolute' => TRUE)));
+      drupal_goto('user/' . $user->uid);
     }
 
     $form['#attached']['library'][] = array('system', 'jquery.cookie');
@@ -46,7 +44,7 @@ public function form(array $form, array &$form_state) {
     // setting is not on.
     field_attach_form($account, $form, $form_state);
     foreach (field_info_instances('user', 'user') as $field_name => $instance) {
-      if (empty($instance['settings']['user_register_form'])) {
+      if (empty($instance->settings['user_register_form'])) {
         $form[$field_name]['#access'] = FALSE;
       }
     }
diff --git a/core/modules/user/lib/Drupal/user/Tests/UserRegistrationTest.php b/core/modules/user/lib/Drupal/user/Tests/UserRegistrationTest.php
index 683bbda..ac11148 100644
--- a/core/modules/user/lib/Drupal/user/Tests/UserRegistrationTest.php
+++ b/core/modules/user/lib/Drupal/user/Tests/UserRegistrationTest.php
@@ -221,6 +221,7 @@ function testRegistrationWithUserFields() {
     // Have the field appear on the registration form.
     $instance->settings['user_register_form'] = TRUE;
     $instance->save();
+
     $this->drupalGet('user/register');
     $this->assertText($instance->label(), 'The field appears on user registration form');
 
diff --git a/core/modules/user/user.install b/core/modules/user/user.install
index 293a45e..5a21e6e3 100644
--- a/core/modules/user/user.install
+++ b/core/modules/user/user.install
@@ -798,7 +798,7 @@ function user_update_8011() {
         'fid' => $default_image_fid,
         'module' => 'image',
         'type' => 'default_image',
-        'id' => $field['uuid'],
+        'id' => $field->uuid,
         'count' => 1,
       ))
       ->execute();
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index bf0b052..9c352ca 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -12,7 +12,6 @@
 use Drupal\user\UserRole;
 use Drupal\user\RoleInterface;
 use Drupal\Core\Template\Attribute;
-use Symfony\Component\HttpFoundation\RedirectResponse;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 use Drupal\menu_link\Plugin\Core\Entity\MenuLink;
 
@@ -2014,7 +2013,7 @@ function user_multiple_cancel_confirm($form, &$form_state) {
     drupal_set_message($message, $redirect ? 'error' : 'warning');
     // If only user 1 was selected, redirect to the overview.
     if ($redirect) {
-      return new RedirectResponse(url('admin/people', array('absolute' => TRUE)));
+      drupal_goto('admin/people');
     }
   }
 
@@ -2367,7 +2366,7 @@ function user_node_load($nodes, $types) {
 function user_form_field_ui_field_instance_edit_form_alter(&$form, &$form_state, $form_id) {
   $instance = $form_state['instance'];
 
-  if ($instance['entity_type'] == 'user') {
+  if ($instance->entity_type == 'user') {
     $form['instance']['settings']['user_register_form'] = array(
       '#type' => 'checkbox',
       '#title' => t('Display on user registration form.'),
@@ -2375,7 +2374,7 @@ function user_form_field_ui_field_instance_edit_form_alter(&$form, &$form_state,
       // Field instances created in D7 beta releases before the setting was
       // introduced might be set as 'required' and 'not shown on user_register
       // form'. We make sure the checkbox comes as 'checked' for those.
-      '#default_value' => $instance['settings']['user_register_form'] || $instance['required'],
+      '#default_value' => $instance->settings['user_register_form'] || $instance->required,
       // Display just below the 'required' checkbox.
       '#weight' => $form['instance']['required']['#weight'] + .1,
       // Disabled when the 'required' checkbox is checked.
@@ -2402,7 +2401,7 @@ function user_form_field_ui_field_instance_edit_form_alter(&$form, &$form_state,
 function user_form_field_ui_field_instance_edit_form_submit($form, &$form_state) {
   $instance = $form_state['values']['instance'];
 
-  if (!empty($instance['required'])) {
+  if (!empty($instance->required)) {
     form_set_value($form['instance']['settings']['user_register_form'], 1, $form_state);
   }
 }
diff --git a/core/modules/user/user.pages.inc b/core/modules/user/user.pages.inc
index a8559d0..26fb040 100644
--- a/core/modules/user/user.pages.inc
+++ b/core/modules/user/user.pages.inc
@@ -112,7 +112,7 @@ function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $a
         drupal_set_message(t('The one-time login link you clicked is invalid.'));
       }
     }
-    return new RedirectResponse(url('<front>', array('absolute' => TRUE)));
+    drupal_goto();
   }
   else {
     // Time out, in seconds, until login URL expires.
@@ -124,7 +124,7 @@ function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $a
       // No time out for first time login.
       if ($account->login && $current - $timestamp > $timeout) {
         drupal_set_message(t('You have tried to use a one-time login link that has expired. Please request a new one using the form below.'));
-        return new RedirectResponse(url('user/password', array('absolute' => TRUE)));
+        drupal_goto('user/password');
       }
       elseif ($account->uid && $timestamp >= $account->login && $timestamp <= $current && $hashed_pass == user_pass_rehash($account->pass, $timestamp, $account->login)) {
         // First stage is a confirmation form, then login
@@ -139,10 +139,7 @@ function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $a
           // Let the user's password be changed without the current password check.
           $token = Crypt::randomStringHashed(55);
           $_SESSION['pass_reset_' . $user->uid] = $token;
-          return new RedirectResponse(url('user/' . $user->uid . '/edit', array(
-            'query' => array('pass-reset-token' => $token),
-            'absolute' => TRUE,
-          )));
+          drupal_goto('user/' . $user->uid . '/edit', array('query' => array('pass-reset-token' => $token)));
         }
         else {
           if (!$account->login) {
@@ -161,7 +158,7 @@ function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $a
       }
       else {
         drupal_set_message(t('You have tried to use a one-time login link that has either been used or is no longer valid. Please request a new one using the form below.'));
-        return new RedirectResponse(url('user/password', array('absolute' => TRUE)));
+        drupal_goto('user/password');
       }
     }
     else {
@@ -392,11 +389,11 @@ function user_cancel_confirm($account, $timestamp = 0, $hashed_pass = '') {
       // Since user_cancel() is not invoked via Form API, batch processing needs
       // to be invoked manually and should redirect to the front page after
       // completion.
-      return batch_process('');
+      batch_process('');
     }
     else {
       drupal_set_message(t('You have tried to use an account cancellation link that has expired. Please request a new one using the form below.'));
-      return new RedirectResponse(url("user/$account->uid/cancel", array('absolute' => TRUE)));
+      drupal_goto("user/$account->uid/cancel");
     }
   }
   throw new AccessDeniedHttpException();
diff --git a/core/modules/views/lib/Drupal/views/Plugin/entity_reference/selection/ViewsSelection.php b/core/modules/views/lib/Drupal/views/Plugin/entity_reference/selection/ViewsSelection.php
index 575c000..a3a6e2e 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/entity_reference/selection/ViewsSelection.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/entity_reference/selection/ViewsSelection.php
@@ -60,11 +60,11 @@ public function __construct(FieldDefinitionInterface $field_definition, EntityIn
    * Implements \Drupal\entity_reference\Plugin\Type\Selection\SelectionInterface::settingsForm().
    */
   public static function settingsForm(&$field, &$instance) {
-    $view_settings = empty($instance['settings']['handler_settings']['view']) ? array() : $instance['settings']['handler_settings']['view'];
+    $view_settings = empty($instance->settings['handler_settings']['view']) ? array() : $instance->settings['handler_settings']['view'];
     $displays = views_get_applicable_views('entity_reference_display');
     // Filter views that list the entity type we want, and group the separate
     // displays by view.
-    $entity_info = entity_get_info($field['settings']['target_type']);
+    $entity_info = entity_get_info($field->settings['target_type']);
     $options = array();
     foreach ($displays as $data) {
       list($view, $display_id) = $data;
diff --git a/core/modules/views/lib/Drupal/views/Tests/Handler/FieldUnitTest.php b/core/modules/views/lib/Drupal/views/Tests/Handler/FieldUnitTest.php
index 14e9197..d7560e1 100644
--- a/core/modules/views/lib/Drupal/views/Tests/Handler/FieldUnitTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/Handler/FieldUnitTest.php
@@ -74,7 +74,7 @@ public function testQuery() {
     $view = views_get_view('test_view');
     $view->initHandlers();
 
-    $id_field = $view->field['id'];
+    $id_field = $view->field->id();
     $id_field->additional_fields['job'] = 'job';
     // Choose also a field alias key which doesn't match to the table field.
     $id_field->additional_fields['created_test'] = array('table' => 'views_test_data', 'field' => 'created');
@@ -151,7 +151,7 @@ public function testRewrite() {
     $view->initHandlers();
     $this->executeView($view);
     $row = $view->result[0];
-    $id_field = $view->field['id'];
+    $id_field = $view->field->id();
 
     // Don't check the rewrite checkbox, so the text shouldn't appear.
     $id_field->options['alter']['text'] = $random_text = $this->randomName();
diff --git a/core/modules/views/lib/Drupal/views/Tests/Handler/FieldWebTest.php b/core/modules/views/lib/Drupal/views/Tests/Handler/FieldWebTest.php
index 6d73636..fc8b80c 100644
--- a/core/modules/views/lib/Drupal/views/Tests/Handler/FieldWebTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/Handler/FieldWebTest.php
@@ -180,7 +180,7 @@ public function testAlterUrl() {
     $view->initHandlers();
     $this->executeView($view);
     $row = $view->result[0];
-    $id_field = $view->field['id'];
+    $id_field = $view->field->id();
 
     // Setup the general settings required to build a link.
     $id_field->options['alter']['make_link'] = TRUE;
@@ -327,7 +327,7 @@ public function testFieldClasses() {
     $view->initHandlers();
 
     // Tests whether the default field classes are added.
-    $id_field = $view->field['id'];
+    $id_field = $view->field->id();
 
     $id_field->options['element_default_classes'] = FALSE;
     $output = $view->preview();
diff --git a/core/modules/views/lib/Drupal/views/Tests/Wizard/TaggedWithTest.php b/core/modules/views/lib/Drupal/views/Tests/Wizard/TaggedWithTest.php
index 2f870d8..c49f67e 100644
--- a/core/modules/views/lib/Drupal/views/Tests/Wizard/TaggedWithTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/Wizard/TaggedWithTest.php
@@ -188,7 +188,7 @@ function testTaggedWithByNodeType() {
     // If we add an instance of the tagging field to the second node type, the
     // "tagged with" form element should not appear for it too.
     $instance = $this->tag_instance;
-    $instance['bundle'] = $this->node_type_without_tags->type;
+    $instance->bundle = $this->node_type_without_tags->type;
     entity_create('field_instance', $instance)->save();
     entity_get_form_display('node', $this->node_type_without_tags->type, 'default')
       ->setComponent('field_views_testing_tags', array(
diff --git a/core/modules/views_ui/admin.inc b/core/modules/views_ui/admin.inc
index 02c62d8..67ed574 100644
--- a/core/modules/views_ui/admin.inc
+++ b/core/modules/views_ui/admin.inc
@@ -226,8 +226,8 @@ function views_ui_taxonomy_autocomplete_validate($element, &$form_state) {
     // vocabulary IDs.
     $field = field_info_field($element['#field_name']);
     $vocabularies = array();
-    if (!empty($field['settings']['allowed_values'])) {
-      foreach ($field['settings']['allowed_values'] as $tree) {
+    if (!empty($field->settings['allowed_values'])) {
+      foreach ($field->settings['allowed_values'] as $tree) {
         if ($vocabulary = entity_load('taxonomy_vocabulary', $tree['vocabulary'])) {
           $vocabularies[$vocabulary->id()] = $tree['vocabulary'];
         }
diff --git a/core/scripts/generate-d7-content.sh b/core/scripts/generate-d7-content.sh
index 87ec22a..8a86cef 100644
--- a/core/scripts/generate-d7-content.sh
+++ b/core/scripts/generate-d7-content.sh
@@ -98,7 +98,7 @@
   foreach ($node_types as $bundle) {
     $instance = array(
       'label' => $vocabulary->name,
-      'field_name' => $field['field_name'],
+      'field_name' => $field->id(),
       'bundle' => $bundle,
       'entity_type' => 'node',
       'settings' => array(),
diff --git a/core/update.php b/core/update.php
index b73e3ce..a3dd4bb 100644
--- a/core/update.php
+++ b/core/update.php
@@ -512,7 +512,7 @@ function update_check_requirements($skip_warnings = FALSE) {
         // update.php correctly by default.
         $batch_url = $base_root . drupal_current_script_url();
         $redirect_url = $base_root . drupal_current_script_url(array('op' => 'results'));
-        $output = update_batch($request->request->get('start'), $redirect_url, $batch_url);
+        update_batch($request->request->get('start'), $redirect_url, $batch_url);
         break;
       }
 
