diff --git a/core/modules/views/src/Plugin/views/PluginBase.php b/core/modules/views/src/Plugin/views/PluginBase.php
index e09545f..1ba0b65 100644
--- a/core/modules/views/src/Plugin/views/PluginBase.php
+++ b/core/modules/views/src/Plugin/views/PluginBase.php
@@ -313,116 +313,14 @@ public function usesOptions() {
   }
 
   /**
-   * {@inheritdoc}
-   */
-  public function globalTokenReplace($string = '', array $options = array()) {
-    return \Drupal::token()->replace($string, array('view' => $this->view), $options);
-  }
-
-  /**
-   * Replaces Views' tokens in a given string. It is the responsibility of the
-   * calling function to ensure $text and $token replacements are sanitized.
+   * Replaces Views' tokens in a given string.
    *
-   * This used to be a simple strtr() scattered throughout the code. Some Views
-   * tokens, such as arguments (e.g.: %1 or !1), still use the old format so we
-   * handle those as well as the new Twig-based tokens (e.g.: {{ field_name }})
+   * @see \Drupal\views\TokenParser::viewsTokenReplace()
    *
-   * @param $text
-   *   String with possible tokens.
-   * @param $tokens
-   *   Array of token => replacement_value items.
-   *
-   * @return String
+   * @todo Remove this wrapper.
    */
   protected function viewsTokenReplace($text, $tokens) {
-    if (empty($tokens)) {
-      return $text;
-    }
-
-    // Separate Twig tokens from other tokens (e.g.: contextual filter tokens in
-    // the form of %1).
-    $twig_tokens = array();
-    $other_tokens = array();
-    foreach ($tokens as $token => $replacement) {
-      if (strpos($token, '{{') !== FALSE) {
-        // Twig wants a token replacement array stripped of curly-brackets.
-        $token = trim(str_replace(array('{', '}'), '', $token));
-        $twig_tokens[$token] = $replacement;
-      }
-      else {
-        $other_tokens[$token] = $replacement;
-      }
-    }
-
-    // Non-Twig tokens are a straight string replacement, Twig tokens get run
-    // through an inline template for rendering and replacement.
-    $text = strtr($text, $other_tokens);
-    if ($twig_tokens) {
-      $build = array(
-        '#type' => 'inline_template',
-        '#template' => $text,
-        '#context' => $twig_tokens,
-      );
-      return drupal_render($build);
-    }
-    else {
-      return $text;
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getAvailableGlobalTokens($prepared = FALSE, array $types = array()) {
-    $info = \Drupal::token()->getInfo();
-    // Site and view tokens should always be available.
-    $types += array('site', 'view');
-    $available = array_intersect_key($info['tokens'], array_flip($types));
-
-    // Construct the token string for each token.
-    if ($prepared) {
-      $prepared = array();
-      foreach ($available as $type => $tokens) {
-        foreach (array_keys($tokens) as $token) {
-          $prepared[$type][] = "[$type:$token]";
-        }
-      }
-
-      return $prepared;
-    }
-
-    return $available;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function globalTokenForm(&$form, FormStateInterface $form_state) {
-    $token_items = array();
-
-    foreach ($this->getAvailableGlobalTokens() as $type => $tokens) {
-      $item = array(
-        '#markup' => $type,
-        'children' => array(),
-      );
-      foreach ($tokens as $name => $info) {
-        $item['children'][$name] = "[$type:$name]" . ' - ' . $info['name'] . ': ' . $info['description'];
-      }
-
-      $token_items[$type] = $item;
-    }
-
-    $form['global_tokens'] = array(
-      '#type' => 'details',
-      '#title' => $this->t('Available global token replacements'),
-    );
-    $form['global_tokens']['list'] = array(
-      '#theme' => 'item_list',
-      '#items' => $token_items,
-      '#attributes' => array(
-        'class' => array('global-tokens'),
-      ),
-    );
+    $this->view->getTokenParser()->viewsTokenReplace($text, $tokens);
   }
 
   /**
diff --git a/core/modules/views/src/Plugin/views/ViewsPluginInterface.php b/core/modules/views/src/Plugin/views/ViewsPluginInterface.php
index d36b4b2..007241d 100644
--- a/core/modules/views/src/Plugin/views/ViewsPluginInterface.php
+++ b/core/modules/views/src/Plugin/views/ViewsPluginInterface.php
@@ -96,31 +96,6 @@ public function init(ViewExecutable $view, DisplayPluginBase $display, array &$o
   public function submitOptionsForm(&$form, FormStateInterface $form_state);
 
   /**
-   * Adds elements for available core tokens to a form.
-   *
-   * @param array $form
-   *   The form array to alter, passed by reference.
-   * @param \Drupal\Core\Form\FormStateInterface $form_state
-   *   The current state of the form.
-   */
-  public function globalTokenForm(&$form, FormStateInterface $form_state);
-
-  /**
-   * Returns an array of available token replacements.
-   *
-   * @param bool $prepared
-   *   Whether to return the raw token info for each token or an array of
-   *   prepared tokens for each type. E.g. "[view:name]".
-   * @param array $types
-   *   An array of additional token types to return, defaults to 'site' and
-   *   'view'.
-   *
-   * @return array
-   *   An array of available token replacement info or tokens, grouped by type.
-   */
-  public function getAvailableGlobalTokens($prepared = FALSE, array $types = array());
-
-  /**
    * Flattens the structure of form elements.
    *
    * If a form element has #flatten = TRUE, then all of it's children get moved
@@ -136,19 +111,6 @@ public function getAvailableGlobalTokens($prepared = FALSE, array $types = array
   public static function preRenderFlattenData($form);
 
   /**
-   * Returns a string with any core tokens replaced.
-   *
-   * @param string $string
-   *   The string to preform the token replacement on.
-   * @param array $options
-   *   An array of options, as passed to \Drupal\Core\Utility\Token::replace().
-   *
-   * @return string
-   *   The tokenized string.
-   */
-  public function globalTokenReplace($string = '', array $options = array());
-
-  /**
    * Clears a plugin.
    */
   public function destroy();
diff --git a/core/modules/views/src/Plugin/views/area/Title.php b/core/modules/views/src/Plugin/views/area/Title.php
index 8843324..93ea0a4 100644
--- a/core/modules/views/src/Plugin/views/area/Title.php
+++ b/core/modules/views/src/Plugin/views/area/Title.php
@@ -41,7 +41,7 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     );
 
     // Don't use the AreaPluginBase tokenForm method, we don't want row tokens.
-    $this->globalTokenForm($form, $form_state);
+    $this->view->getTokenParser()->globalTokenForm($form, $form_state);
   }
 
   /**
@@ -52,7 +52,7 @@ public function preRender(array $results) {
 
     // If a title is provided, process it.
     if (!empty($this->options['title'])) {
-      $value = $this->globalTokenReplace($this->options['title']);
+      $value = $this->view->getTokenParser()->globalTokenReplace($this->options['title']);
       $this->view->setTitle($this->sanitizeValue($value, 'xss_admin'));
     }
   }
diff --git a/core/modules/views/src/Plugin/views/area/TokenizeAreaPluginBase.php b/core/modules/views/src/Plugin/views/area/TokenizeAreaPluginBase.php
index bf6fbf6..f2f02f5 100644
--- a/core/modules/views/src/Plugin/views/area/TokenizeAreaPluginBase.php
+++ b/core/modules/views/src/Plugin/views/area/TokenizeAreaPluginBase.php
@@ -42,6 +42,8 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
 
   /**
    * Adds tokenization form elements.
+   *
+   * @todo This needs an update for https://www.drupal.org/node/2342287.
    */
   public function tokenForm(&$form, FormStateInterface $form_state) {
     $form['tokenize'] = array(
@@ -91,7 +93,7 @@ public function tokenForm(&$form, FormStateInterface $form_state) {
       }
     }
 
-    $this->globalTokenForm($form, $form_state);
+    $this->view->getTokenParser()->globalTokenForm($form, $form_state);
   }
 
   /**
@@ -106,10 +108,10 @@ public function tokenForm(&$form, FormStateInterface $form_state) {
    */
   public function tokenizeValue($value) {
     if ($this->options['tokenize']) {
-      $value = $this->view->style_plugin->tokenizeValue($value, 0);
+      $value = $this->view->getStyle()->tokenizeValue($value, 0);
     }
     // As we add the globalTokenForm() we also should replace the token here.
-    return $this->globalTokenReplace($value);
+    return $this->view->getTokenParser()->globalTokenReplace($value);
   }
 
 }
diff --git a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
index 61c9e84..de67e49 100644
--- a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
+++ b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
@@ -1053,7 +1053,7 @@ public function optionLink($text, $section, $class = '', $title = '') {
    * This function is similar to views_handler_field::getRenderTokens()
    * but without fields tokens.
    */
-  public function getArgumentsTokens() {
+  public function getArgumentTokens() {
     $tokens = array();
     if (!empty($this->view->build_info['substitutions'])) {
       $tokens = $this->view->build_info['substitutions'];
@@ -1065,9 +1065,9 @@ public function getArgumentsTokens() {
       if (!isset($tokens["%$count"])) {
         $tokens["%$count"] = '';
       }
-       // Use strip tags as there should never be HTML in the path.
-       // However, we need to preserve special characters like " that
-       // were removed by String::checkPlain().
+      // Use strip tags as there should never be HTML in the path.
+      // However, we need to preserve special characters like " that
+      // were removed by String::checkPlain().
       $tokens["!$count"] = isset($this->view->args[$count - 1]) ? strip_tags(String::decodeEntities($this->view->args[$count - 1])) : '';
     }
 
@@ -2131,7 +2131,7 @@ public function renderMoreLink() {
       $path = $this->getPath();
 
       if ($this->getOption('link_display') == 'custom_url' && $override_path = $this->getOption('link_url')) {
-        $tokens = $this->getArgumentsTokens();
+        $tokens = $this->getArgumentTokens();
         $path = $this->viewsTokenReplace($override_path, $tokens);
       }
 
diff --git a/core/modules/views/src/Plugin/views/field/FieldPluginBase.php b/core/modules/views/src/Plugin/views/field/FieldPluginBase.php
index 74c8620..7f569be 100644
--- a/core/modules/views/src/Plugin/views/field/FieldPluginBase.php
+++ b/core/modules/views/src/Plugin/views/field/FieldPluginBase.php
@@ -331,7 +331,7 @@ public function elementClasses($row_index = NULL) {
    * {@inheritdoc}
    */
   public function tokenizeValue($value, $row_index = NULL) {
-    if (strpos($value, '{{') !== FALSE || strpos($value, '!') !== FALSE || strpos($value, '%') !== FALSE) {
+    if ($this->view->getTokenParser()->hasRenderToken($value) || $this->view->getTokenParser()->hasArgumentToken($value)) {
       $fake_item = array(
         'alter_text' => TRUE,
         'text' => $value,
@@ -1468,22 +1468,7 @@ protected function renderAsLink($alter, $text, $tokens) {
    * {@inheritdoc}
    */
   public function getRenderTokens($item) {
-    $tokens = array();
-    if (!empty($this->view->build_info['substitutions'])) {
-      $tokens = $this->view->build_info['substitutions'];
-    }
-    $count = 0;
-    foreach ($this->view->display_handler->getHandlers('argument') as $arg => $handler) {
-      $token = '%' . ++$count;
-      if (!isset($tokens[$token])) {
-        $tokens[$token] = '';
-      }
-
-      // Use strip tags as there should never be HTML in the path.
-      // However, we need to preserve special characters like " that
-      // were removed by String::checkPlain().
-      $tokens['!' . $count] = isset($this->view->args[$count - 1]) ? strip_tags(String::decodeEntities($this->view->args[$count - 1])) : '';
-    }
+    $tokens = $this->view->display_handler->getArgumentTokens();
 
     // Get flattened set of tokens for any array depth in query parameters.
     $tokens += $this->getTokenValuesRecursive($this->view->getRequest()->query->all());
diff --git a/core/modules/views/src/Plugin/views/style/StylePluginBase.php b/core/modules/views/src/Plugin/views/style/StylePluginBase.php
index 9c229da..fe11fc2 100644
--- a/core/modules/views/src/Plugin/views/style/StylePluginBase.php
+++ b/core/modules/views/src/Plugin/views/style/StylePluginBase.php
@@ -184,20 +184,6 @@ function usesFields() {
   }
 
   /**
-   * Return TRUE if this style uses tokens.
-   *
-   * Used to ensure we don't fetch tokens when not needed for performance.
-   */
-  public function usesTokens() {
-    if ($this->usesRowClass()) {
-      $class = $this->options['row_class'];
-      if (strpos($class, '{{') !== FALSE || strpos($class, '!') !== FALSE || strpos($class, '%') !== FALSE) {
-        return TRUE;
-      }
-    }
-  }
-
-  /**
    * Return TRUE if this style enables field labels by default.
    *
    * @return bool
@@ -228,14 +214,14 @@ public function getRowClass($row_index) {
    * Take a value and apply token replacement logic to it.
    */
   public function tokenizeValue($value, $row_index) {
-    if (strpos($value, '{{') !== FALSE || strpos($value, '!') !== FALSE || strpos($value, '%') !== FALSE) {
+    if ($this->view->getTokenParser()->hasArgumentToken($value) || $this->view->getTokenParser()->hasRenderToken($value)) {
       // Row tokens might be empty, for example for node row style.
       $tokens = isset($this->rowTokens[$row_index]) ? $this->rowTokens[$row_index] : array();
       if (!empty($this->view->build_info['substitutions'])) {
         $tokens += $this->view->build_info['substitutions'];
       }
 
-      $value = $this->viewsTokenReplace($value, $tokens);
+      $value = $this->view->getTokenParser()->viewsTokenReplace($value, $tokens);
     }
     return $value;
   }
diff --git a/core/modules/views/src/Tests/Handler/AreaTest.php b/core/modules/views/src/Tests/Handler/AreaTest.php
index 03b8b57..6fa059c 100644
--- a/core/modules/views/src/Tests/Handler/AreaTest.php
+++ b/core/modules/views/src/Tests/Handler/AreaTest.php
@@ -170,7 +170,7 @@ public function testRenderAreaToken() {
     $empty_handler = &$view->empty['test_example'];
 
     // Test the list of available tokens.
-    $available = $empty_handler->getAvailableGlobalTokens();
+    $available = $empty_handler->view->getTokenParser()->getAvailableGlobalTokens();
     foreach (array('site', 'view') as $type) {
       $this->assertTrue(!empty($available[$type]) && is_array($available[$type]));
       // Test that each item exists in the list.
diff --git a/core/modules/views/src/TokenParser.php b/core/modules/views/src/TokenParser.php
new file mode 100644
index 0000000..661d271
--- /dev/null
+++ b/core/modules/views/src/TokenParser.php
@@ -0,0 +1,249 @@
+<?php
+/**
+ * @file Contains \Drupal\views\TokenParser.
+ */
+
+namespace Drupal\views;
+
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\Core\Utility\Token;
+
+/**
+ * Provides a utility for parsing tokens within Views.
+ *
+ * Three kinds of tokens are used within Views:
+ * - Argument tokens: These Views tokens represent an argument (contextual
+ *   filter) passed to the View, for example %1 or !1.
+ * - Render tokens: These Views tokens represent the rendered output of a field
+ *   on the view, for example, {{ title }}.
+ * - Global tokens: These global tokens are provided by the token utility,
+ *   for example [node:title].
+ *
+ * @see \Drupal\Core\Utility\Token
+ *
+ * @todo Explain the difference between %1 and !1.
+ * @todo What to do with:
+ *   - StylePluginBase::tokenizeValue()
+ *   - FieldHandlerInterface::tokenizeValue()
+ *   - TokenizeAreaPluginBase::tokenizeValue()
+ *   - FieldHandlerInterface::getRenderTokens()
+ *   - FieldHandlerInterface::getTokenValuesRecursive()
+ *   - DisplayPluginBase::getArgumentTokens()
+ *   - TokenizeAreaPluginBase::tokenForm()
+ */
+class TokenParser {
+
+  use StringTranslationTrait;
+
+  /**
+   * The top object of the view.
+   *
+   * @var \Drupal\views\ViewExecutable
+   */
+  protected $view;
+
+  /**
+   * The global token utility.
+   *
+   * @var \Drupal\Core\Utility\Token
+   */
+  protected $tokenUtility;
+
+  /**
+   * Constructs a Views token parser object.
+   *
+   * @param Token $token_utility
+   */
+  public function __construct(ViewExecutable $view, Token $token_utility) {
+    $this->view = $view;
+    $this->tokenUtility = $token_utility;
+  }
+
+  /**
+   * Returns a string with any core tokens replaced.
+   *
+   * @param string $string
+   *   The string to preform the token replacement on.
+   * @param array $options
+   *   An array of options, as passed to \Drupal\Core\Utility\Token::replace().
+   *
+   * @return string
+   *   The tokenized string.
+   */
+  public function globalTokenReplace($string = '', array $options = array()) {
+    return $this->tokenUtility->replace($string, array('view' => $this->view), $options);
+  }
+
+  /**
+   * Indicates whether the value has a potential Views argument token.
+   *
+   * @param string $value
+   *   The string to check
+   *
+   * @return bool
+   *   TRUE if the string has a potential Views argument token.
+   *
+   * @see \Drupal\views\Plugin\views\display\DisplayPluginBase::getArgumentTokens()
+   */
+  public function hasArgumentToken($value) {
+    // If the string definitely does not contain a token, return FALSE
+    // immediately for performance.
+    if ((strpos($value, '!') === FALSE) && (strpos($value, '%') === FALSE)) {
+      return FALSE;
+    }
+    // Otherwise, scan for valid token patterns.
+    return preg_match('/[!%]\d+/', $value);
+  }
+
+  /**
+   * Indicates whether the value has a potential Views row-level token.
+   *
+   * @param string $value
+   *   The string to check
+   *
+   * @return bool
+   *   TRUE if the string has a potential row token.
+   *
+   * @see \Drupal\views\Plugin\views\field\FieldPluginBase::getRenderTokens()
+   */
+  public function hasRenderToken($value) {
+    // If the string definitely does not contain a token, return FALSE
+    // immediately for performance.
+    if (strpos($value, '{{') === FALSE) {
+      return FALSE;
+    }
+    // Otherwise, scan for valid token patterns.
+    // Match any non-empty string between {{ and }} except another {{.
+    return preg_match('/\{\{[^(\{\{)]+\}\}/', $value);
+  }
+
+  /**
+   * Indicates whether the value has a potential Views token.
+   *
+   * @param string $value
+   *   The string to check
+   *
+   * @return bool
+   *   TRUE if the string has any token pattern.
+   */
+  public function hasToken($value) {
+    return ($this->hasArgumentToken($value) || $this->hasRenderToken($value));
+  }
+
+  /**
+   * Replaces Views' tokens in a given string.
+   *
+   * It is the responsibility of the calling function to ensure $text and
+   * $token replacements are sanitized.
+   *
+   * @param $text
+   *   String with possible tokens.
+   * @param $tokens
+   *   Array of token => replacement_value items.
+   *
+   * @return String
+   *   The text with the tokens replaced.
+   *
+   * @see \Drupal\views\TokenParser::hasToken()
+   * @see \Drupal\views\Plugin\views\display\DisplayPluginBase::getArgumentTokens()
+   * @see \Drupal\views\Plugin\views\field\FieldPluginBase::getRenderTokens()
+   */
+  public function viewsTokenReplace($text, $tokens) {
+    if (empty($tokens)) {
+      return $text;
+    }
+
+    // Separate Twig tokens from other tokens (e.g.: contextual filter tokens in
+    // the form of %1).
+    $twig_tokens = array();
+    $other_tokens = array();
+    foreach ($tokens as $token => $replacement) {
+      if ($this->hasRenderToken($token)) {
+        // Twig wants a token replacement array stripped of curly-brackets.
+        // @todo Do this with the regex instead.
+        $token = trim(str_replace(array('{', '}'), '', $token));
+        $twig_tokens[$token] = $replacement;
+      }
+      else {
+        $other_tokens[$token] = $replacement;
+      }
+    }
+
+    // Non-Twig tokens are a straight string replacement, Twig tokens get run
+    // through an inline template for rendering and replacement.
+    $text = strtr($text, $other_tokens);
+    if ($twig_tokens) {
+      $build = array(
+        '#type' => 'inline_template',
+        '#template' => $text,
+        '#context' => $twig_tokens,
+      );
+      return drupal_render($build);
+    }
+    else {
+      return $text;
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getAvailableGlobalTokens($prepared = FALSE, array $types = array()) {
+    $info = $this->tokenUtility->getInfo();
+    // Site and view tokens should always be available.
+    $types += array('site', 'view');
+    $available = array_intersect_key($info['tokens'], array_flip($types));
+
+    // Construct the token string for each token.
+    if ($prepared) {
+      $prepared = array();
+      foreach ($available as $type => $tokens) {
+        foreach (array_keys($tokens) as $token) {
+          $prepared[$type][] = "[$type:$token]";
+        }
+      }
+
+      return $prepared;
+    }
+
+    return $available;
+  }
+
+  /**
+   * Adds elements for available core tokens to a form.
+   *
+   * @param array $form
+   *   The form array to alter, passed by reference.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
+   */
+  public function globalTokenForm(&$form, FormStateInterface $form_state) {
+    $token_items = array();
+
+    foreach ($this->getAvailableGlobalTokens() as $type => $tokens) {
+      $item = array(
+        '#markup' => $type,
+        'children' => array(),
+      );
+      foreach ($tokens as $name => $info) {
+        $item['children'][$name] = "[$type:$name]" . ' - ' . $info['name'] . ': ' . $info['description'];
+      }
+
+      $token_items[$type] = $item;
+    }
+
+    $form['global_tokens'] = array(
+      '#type' => 'details',
+      '#title' => $this->t('Available global token replacements'),
+    );
+    $form['global_tokens']['list'] = array(
+      '#theme' => 'item_list',
+      '#items' => $token_items,
+      '#attributes' => array(
+        'class' => array('global-tokens'),
+      ),
+    );
+  }
+
+}
diff --git a/core/modules/views/src/ViewExecutable.php b/core/modules/views/src/ViewExecutable.php
index 670d819..611f506 100644
--- a/core/modules/views/src/ViewExecutable.php
+++ b/core/modules/views/src/ViewExecutable.php
@@ -11,6 +11,7 @@
 use Drupal\Core\DependencyInjection\DependencySerializationTrait;
 use Drupal\Core\Form\FormState;
 use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\Utility\Token;
 use Drupal\views\Plugin\views\query\QueryPluginBase;
 use Drupal\views\ViewEntityInterface;
 use Drupal\Component\Utility\Tags;
@@ -425,6 +426,20 @@ class ViewExecutable {
   protected $viewsData;
 
   /**
+   * The global token utility.
+   *
+   * @var \Drupal\Core\Utility\TokenUtility
+   */
+  protected $tokenUtility;
+
+  /**
+   * The token parser for the view.
+   *
+   * @var \Drupal\views\TokenParser
+   */
+  protected $tokenParser;
+
+  /**
    * Constructs a new ViewExecutable object.
    *
    * @param \Drupal\views\ViewEntityInterface $storage
@@ -433,16 +448,20 @@ class ViewExecutable {
    *   The current user.
    * @param \Drupal\views\ViewsData $views_data
    *   The views data.
+   * @param \Drupal\Core\Utility\Token $token_utility
+   *   The global token utility.
    */
-  public function __construct(ViewEntityInterface $storage, AccountInterface $user, ViewsData $views_data) {
+  public function __construct(ViewEntityInterface $storage, AccountInterface $user, ViewsData $views_data, Token $token_utility) {
     // Reference the storage and the executable to each other.
     $this->storage = $storage;
     $this->storage->set('executable', $this);
     $this->user = $user;
     $this->viewsData = $views_data;
+    $this->tokenUtility = $token_utility;
 
     // Add the default css for a view.
     $this->element['#attached']['library'][] = 'views/views.module';
+    $this->tokenParser = new TokenParser($this, $this->tokenUtility);
   }
 
   /**
@@ -461,6 +480,16 @@ public function setArguments($args) {
   }
 
   /**
+   * Returns the view's token parser.
+   *
+   * @return \Drupal\views\TokenParser
+   *   The token parser for the view.
+   */
+  public function getTokenParser() {
+    return $this->tokenParser;
+  }
+
+  /**
    * Change/Set the current page for the pager.
    */
   public function setCurrentPage($page) {
diff --git a/core/modules/views/src/ViewExecutableFactory.php b/core/modules/views/src/ViewExecutableFactory.php
index 04f6196..a0b407c 100644
--- a/core/modules/views/src/ViewExecutableFactory.php
+++ b/core/modules/views/src/ViewExecutableFactory.php
@@ -8,6 +8,7 @@
 namespace Drupal\views;
 
 use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\Utility\Token;
 use Drupal\views\ViewEntityInterface;
 use Symfony\Component\HttpFoundation\RequestStack;
 
@@ -38,6 +39,13 @@ class ViewExecutableFactory {
   protected $viewsData;
 
   /**
+   * The global token utility.
+   *
+   * @var \Drupal\Core\Utility\Token
+   */
+  protected $tokenUtility;
+
+  /**
    * Constructs a new ViewExecutableFactory
    *
    * @param \Drupal\Core\Session\AccountInterface $user
@@ -46,11 +54,14 @@ class ViewExecutableFactory {
    *   The request stack.
    * @param \Drupal\views\ViewsData $views_data
    *   The views data.
+   * @param \Drupal\Core\Utility\Token $token_utility
+   *   The token utility.
    */
-  public function __construct(AccountInterface $user, RequestStack $request_stack, ViewsData $views_data) {
+  public function __construct(AccountInterface $user, RequestStack $request_stack, ViewsData $views_data, Token $token_utility) {
     $this->user = $user;
     $this->requestStack = $request_stack;
     $this->viewsData = $views_data;
+    $this->tokenUtility = $token_utility;
   }
 
   /**
@@ -63,7 +74,7 @@ public function __construct(AccountInterface $user, RequestStack $request_stack,
    *   A ViewExecutable instance.
    */
   public function get(ViewEntityInterface $view) {
-    $view = new ViewExecutable($view, $this->user, $this->viewsData);
+    $view = new ViewExecutable($view, $this->user, $this->viewsData, $this->tokenUtility);
     $view->setRequest($this->requestStack->getCurrentRequest());
     return $view;
   }
diff --git a/core/modules/views/tests/modules/views_test_data/src/Plugin/views/area/TestExample.php b/core/modules/views/tests/modules/views_test_data/src/Plugin/views/area/TestExample.php
index 1bcf2f4..f048480 100644
--- a/core/modules/views/tests/modules/views_test_data/src/Plugin/views/area/TestExample.php
+++ b/core/modules/views/tests/modules/views_test_data/src/Plugin/views/area/TestExample.php
@@ -43,7 +43,7 @@ public function defineOptions() {
    */
   public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
-    $this->globalTokenForm($form, $form_state);
+    $this->view->getTokenParser()->globalTokenForm($form, $form_state);
   }
 
   /**
@@ -52,7 +52,7 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
   public function render($empty = FALSE) {
     if (!$empty || !empty($this->options['empty'])) {
       return array(
-        '#markup' => $this->globalTokenReplace($this->options['string']),
+        '#markup' => $this->view->getTokenParser()->globalTokenReplace($this->options['string']),
       );
     }
     return array();
diff --git a/core/modules/views/tests/src/Unit/Plugin/area/ResultTest.php b/core/modules/views/tests/src/Unit/Plugin/area/ResultTest.php
index a289d8e..53acc30 100644
--- a/core/modules/views/tests/src/Unit/Plugin/area/ResultTest.php
+++ b/core/modules/views/tests/src/Unit/Plugin/area/ResultTest.php
@@ -46,7 +46,10 @@ protected function setUp() {
     $views_data = $this->getMockBuilder('Drupal\views\ViewsData')
       ->disableOriginalConstructor()
       ->getMock();
-    $this->view = new ViewExecutable($storage, $user, $views_data);
+    $token_utility = $this->getMockBuilder('Drupal\Core\Utility\Token')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $this->view = new ViewExecutable($storage, $user, $views_data, $token_utility);
 
     $this->resultHandler = new Result(array(), 'result', array());
     $this->resultHandler->view = $this->view;
diff --git a/core/modules/views/tests/src/Unit/Plugin/field/CounterTest.php b/core/modules/views/tests/src/Unit/Plugin/field/CounterTest.php
index 959ce3d..bb611b1 100644
--- a/core/modules/views/tests/src/Unit/Plugin/field/CounterTest.php
+++ b/core/modules/views/tests/src/Unit/Plugin/field/CounterTest.php
@@ -75,7 +75,10 @@ protected function setUp() {
     $views_data = $this->getMockBuilder('Drupal\views\ViewsData')
       ->disableOriginalConstructor()
       ->getMock();
-    $this->view = $this->getMock('Drupal\views\ViewExecutable', NULL, array($storage, $user, $views_data));
+    $token_utility = $this->getMockBuilder('Drupal\Core\Utility\Token')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $this->view = $this->getMock('Drupal\views\ViewExecutable', NULL, array($storage, $user, $views_data, $token_utility));
 
     $this->display = $this->getMockBuilder('Drupal\views\Plugin\views\display\DisplayPluginBase')
       ->disableOriginalConstructor()
diff --git a/core/modules/views/tests/src/Unit/PluginBaseTest.php b/core/modules/views/tests/src/Unit/PluginBaseTest.php
index 9c180a6..ee562c3 100644
--- a/core/modules/views/tests/src/Unit/PluginBaseTest.php
+++ b/core/modules/views/tests/src/Unit/PluginBaseTest.php
@@ -319,5 +319,4 @@ public function providerTestFilterByDefinedOptions() {
 
     return $data;
   }
-
 }
diff --git a/core/modules/views/tests/src/Unit/ViewExecutableFactoryTest.php b/core/modules/views/tests/src/Unit/ViewExecutableFactoryTest.php
index e82468e..c9788ae 100644
--- a/core/modules/views/tests/src/Unit/ViewExecutableFactoryTest.php
+++ b/core/modules/views/tests/src/Unit/ViewExecutableFactoryTest.php
@@ -54,6 +54,13 @@ class ViewExecutableFactoryTest extends UnitTestCase {
   protected $viewsData;
 
   /**
+   * The global token utility.
+   *
+   * @var \Drupal\Core\Utility\Token
+   */
+  protected $tokenUtility;
+
+  /**
    * {@inheritdoc}
    */
   protected function setUp() {
@@ -65,7 +72,10 @@ protected function setUp() {
     $this->viewsData = $this->getMockBuilder('Drupal\views\ViewsData')
       ->disableOriginalConstructor()
       ->getMock();
-    $this->viewExecutableFactory = new ViewExecutableFactory($this->user, $this->requestStack, $this->viewsData);
+    $this->tokenUtility = $this->getMockBuilder('Drupal\Core\Utility\Token')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $this->viewExecutableFactory = new ViewExecutableFactory($this->user, $this->requestStack, $this->viewsData, $this->tokenUtility);
   }
 
   /**
diff --git a/core/modules/views/tests/src/Unit/ViewExecutableUnitTest.php b/core/modules/views/tests/src/Unit/ViewExecutableUnitTest.php
index ecabe3f..2331e75 100644
--- a/core/modules/views/tests/src/Unit/ViewExecutableUnitTest.php
+++ b/core/modules/views/tests/src/Unit/ViewExecutableUnitTest.php
@@ -280,7 +280,10 @@ protected function setupBaseViewAndDisplay() {
     );
 
     $storage = new View($config, 'view');
-    $view = new ViewExecutable($storage, $this->user, $this->viewsData);
+    $token_utility = $this->getMockBuilder('Drupal\Core\Utility\Token')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $view = new ViewExecutable($storage, $this->user, $this->viewsData, $token_utility);
     $display = $this->getMockBuilder('Drupal\views\Plugin\views\display\DisplayPluginBase')
       ->disableOriginalConstructor()
       ->getMock();
diff --git a/core/modules/views/tests/src/Unit/ViewsTest.php b/core/modules/views/tests/src/Unit/ViewsTest.php
index ab9bdf8..a5c170d 100644
--- a/core/modules/views/tests/src/Unit/ViewsTest.php
+++ b/core/modules/views/tests/src/Unit/ViewsTest.php
@@ -34,7 +34,10 @@ protected function setUp() {
     $views_data = $this->getMockBuilder('Drupal\views\ViewsData')
       ->disableOriginalConstructor()
       ->getMock();
-    $container->set('views.executable', new ViewExecutableFactory($user, $request_stack, $views_data));
+    $token_utility = $this->getMockBuilder('Drupal\Core\Utility\Token')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $container->set('views.executable', new ViewExecutableFactory($user, $request_stack, $views_data, $token_utility));
 
     $this->view = new View(array('id' => 'test_view'), 'view');
 
diff --git a/core/modules/views/views.services.yml b/core/modules/views/views.services.yml
index 9654432..06ea2da 100644
--- a/core/modules/views/views.services.yml
+++ b/core/modules/views/views.services.yml
@@ -64,7 +64,7 @@ services:
     arguments: ['@views.views_data']
   views.executable:
     class: Drupal\views\ViewExecutableFactory
-    arguments: ['@current_user', '@request_stack', '@views.views_data']
+    arguments: ['@current_user', '@request_stack', '@views.views_data', '@token']
   views.analyzer:
     class: Drupal\views\Analyzer
     arguments: ['@module_handler']
diff --git a/core/modules/views_ui/tests/src/Unit/ViewListBuilderTest.php b/core/modules/views_ui/tests/src/Unit/ViewListBuilderTest.php
index b77f595..7511e6c 100644
--- a/core/modules/views_ui/tests/src/Unit/ViewListBuilderTest.php
+++ b/core/modules/views_ui/tests/src/Unit/ViewListBuilderTest.php
@@ -125,7 +125,10 @@ public function testBuildRowEntityList() {
     $views_data = $this->getMockBuilder('Drupal\views\ViewsData')
       ->disableOriginalConstructor()
       ->getMock();
-    $executable_factory = new ViewExecutableFactory($user, $request_stack, $views_data);
+    $token_utility = $this->getMockBuilder('Drupal\Core\Utility\Token')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $executable_factory = new ViewExecutableFactory($user, $request_stack, $views_data, $token_utility);
     $container->set('views.executable', $executable_factory);
     $container->set('plugin.manager.views.display', $display_manager);
     \Drupal::setContainer($container);
