diff --git a/core/modules/field/field.module b/core/modules/field/field.module
index d09049e..2529228 100644
--- a/core/modules/field/field.module
+++ b/core/modules/field/field.module
@@ -12,6 +12,7 @@
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Url;
 use Drupal\field\Entity\FieldStorageConfig;
+use Drupal\Component\Utility\SafeMarkup;

 /*
  * Load all public Field API functions. Drupal currently has no
@@ -304,3 +305,49 @@ function field_form_config_admin_import_form_alter(&$form, FormStateInterface $f
     }
   }
 }
+
+/**
+ * Implements hook_token_info().
+ */
+function field_token_info() {
+  return [
+    'types' => [
+      'field-storage' => [
+        'name' => t('Field storage'),
+        'description' => t('Tokens related to field storage items.'),
+        'needs-data' => 'field-storage',
+      ],
+    ],
+    'tokens' => [
+      'field-storage' => [
+        'name' => [
+          'name' => t('Field name'),
+          'description' => t('Machine name of the field.'),
+        ],
+      ],
+    ],
+  ];
+}
+
+/**
+ * Implements hook_tokens().
+ */
+function field_tokens($type, $tokens, array $data = array(), array $options = array()) {
+  $sanitize = !empty($options['sanitize']);
+  $replacements = [];
+
+  if ($type == 'field-storage' && !empty($data['field-storage'])) {
+    /** @var \Drupal\Core\Field\FieldStorageDefinitionInterface $field_storage */
+    $field_storage = $data['field-storage'];
+
+    foreach ($tokens as $name => $original) {
+      switch ($name) {
+        case 'name':
+          $replacements[$original] = $sanitize ? SafeMarkup::checkPlain($field_storage->getName()) : $field_storage->getName();
+          break;
+      }
+    }
+  }
+
+  return $replacements;
+}
diff --git a/core/modules/file/src/Plugin/Field/FieldType/FileItem.php b/core/modules/file/src/Plugin/Field/FieldType/FileItem.php
index 7722e66..e15d80e 100644
--- a/core/modules/file/src/Plugin/Field/FieldType/FileItem.php
+++ b/core/modules/file/src/Plugin/Field/FieldType/FileItem.php
@@ -50,7 +50,7 @@ public static function defaultStorageSettings() {
   public static function defaultFieldSettings() {
     return array(
       'file_extensions' => 'txt',
-      'file_directory' => '',
+      'file_directory' => 'field/[field-storage:name]/[date:custom:Y]/[date:custom:m]',
       'max_filesize' => '',
       'description_field' => 0,
     ) + parent::defaultFieldSettings();
@@ -268,6 +268,8 @@ public function getUploadLocation($data = array()) {
     $settings = $this->getSettings();
     $destination = trim($settings['file_directory'], '/');

+    $data += ['field-storage' => $this->getFieldDefinition()->getFieldStorageDefinition()];
+
     // Replace tokens.
     $destination = \Drupal::token()->replace($destination, $data);

@@ -311,6 +313,7 @@ public static function generateSampleValue(FieldDefinitionInterface $field_defin

     // Prepare destination.
     $dirname = $settings['uri_scheme'] . '://' . $settings['file_directory'];
+    $dirname = \Drupal::token()->replace($dirname, ['field-storage' => $field_definition->getFieldStorageDefinition()]);
     file_prepare_directory($dirname, FILE_CREATE_DIRECTORY);

     // Generate a file entity.
diff --git a/core/modules/file/src/Tests/FileFieldPathTest.php b/core/modules/file/src/Tests/FileFieldPathTest.php
index 346fc7a..49ce74c 100644
--- a/core/modules/file/src/Tests/FileFieldPathTest.php
+++ b/core/modules/file/src/Tests/FileFieldPathTest.php
@@ -19,20 +19,30 @@ class FileFieldPathTest extends FileFieldTestBase {
    * Tests the normal formatter display on node display.
    */
   function testUploadPath() {
+    /** @var \Drupal\node\NodeStorageInterface $node_storage */
     $node_storage = $this->container->get('entity.manager')->getStorage('node');
     $field_name = strtolower($this->randomMachineName());
     $type_name = 'article';
     $this->createFileField($field_name, 'node', $type_name);
+    /** @var \Drupal\file\FileInterface $test_file */
     $test_file = $this->getTestFile('text');

     // Create a new node.
     $nid = $this->uploadNodeFile($test_file, $field_name, $type_name);

-    // Check that the file was uploaded to the file root.
+    // Check that the file was uploaded to the correct location.
     $node_storage->resetCache(array($nid));
     $node = $node_storage->load($nid);
-    $node_file = File::load($node->{$field_name}->target_id);
-    $this->assertPathMatch('public://' . $test_file->getFilename(), $node_file->getFileUri(), format_string('The file %file was uploaded to the correct path.', array('%file' => $node_file->getFileUri())));
+    /** @var \Drupal\file\FileInterface $node_file */
+    $node_file = $node->{$field_name}->entity;
+    $date_formatter = $this->container->get('date.formatter');
+    $expected_filename =
+      'public://field/' .
+      $field_name . '/' .
+      $date_formatter->format(REQUEST_TIME, 'custom', 'Y') . '/' .
+      $date_formatter->format(REQUEST_TIME, 'custom', 'm') . '/' .
+      $test_file->getFilename();
+    $this->assertPathMatch($expected_filename, $node_file->getFileUri(), format_string('The file %file was uploaded to the correct path.', array('%file' => $node_file->getFileUri())));

     // Change the path to contain multiple subdirectories.
     $this->updateFileField($field_name, $type_name, array('file_directory' => 'foo/bar/baz'));
