diff --git a/core/lib/Drupal/Core/Http/FileBag.php b/core/lib/Drupal/Core/Http/FileBag.php
new file mode 100644
index 0000000000..24c93a837b
--- /dev/null
+++ b/core/lib/Drupal/Core/Http/FileBag.php
@@ -0,0 +1,136 @@
+<?php
+
+namespace Drupal\Core\Http;
+
+use Symfony\Component\HttpFoundation\File\UploadedFile;
+
+/**
+ * FileBag is a container for uploaded files.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ * @author Bulat Shakirzyanov <mallluhuct@gmail.com>
+ */
+class FileBag extends ParameterBagWithBc
+{
+    private static $fileKeys = array('error', 'name', 'size', 'tmp_name', 'type');
+
+    /**
+     * Constructor.
+     *
+     * @param array $parameters An array of HTTP files
+     */
+    public function __construct(array $parameters = array())
+    {
+        $this->replace($parameters);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function replace(array $files = array())
+    {
+        $this->parameters = array();
+        $this->add($files);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function set($key, $value)
+    {
+        if (!is_array($value) && !$value instanceof UploadedFile) {
+            throw new \InvalidArgumentException('An uploaded file must be an array or an instance of UploadedFile.');
+        }
+
+        parent::set($key, $this->convertFileInformation($value));
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function add(array $files = array())
+    {
+        foreach ($files as $key => $file) {
+            $this->set($key, $file);
+        }
+    }
+
+    /**
+     * Converts uploaded files to UploadedFile instances.
+     *
+     * @param array|UploadedFile $file A (multi-dimensional) array of uploaded file information
+     *
+     * @return UploadedFile|UploadedFile[] A (multi-dimensional) array of UploadedFile instances
+     */
+    protected function convertFileInformation($file)
+    {
+        if ($file instanceof UploadedFile) {
+            return $file;
+        }
+
+        $file = $this->fixPhpFilesArray($file);
+        if (is_array($file)) {
+            $keys = array_keys($file);
+            sort($keys);
+
+            if ($keys == self::$fileKeys) {
+                if (UPLOAD_ERR_NO_FILE == $file['error']) {
+                    $file = null;
+                } else {
+                    $file = new UploadedFile($file['tmp_name'], $file['name'], $file['type'], $file['size'], $file['error']);
+                }
+            } else {
+                $file = array_map(array($this, 'convertFileInformation'), $file);
+            }
+        }
+
+        return $file;
+    }
+
+    /**
+     * Fixes a malformed PHP $_FILES array.
+     *
+     * PHP has a bug that the format of the $_FILES array differs, depending on
+     * whether the uploaded file fields had normal field names or array-like
+     * field names ("normal" vs. "parent[child]").
+     *
+     * This method fixes the array to look like the "normal" $_FILES array.
+     *
+     * It's safe to pass an already converted array, in which case this method
+     * just returns the original array unmodified.
+     *
+     * @param array $data
+     *
+     * @return array
+     */
+    protected function fixPhpFilesArray($data)
+    {
+        if (!is_array($data)) {
+            return $data;
+        }
+
+        $keys = array_keys($data);
+        sort($keys);
+
+        if (self::$fileKeys != $keys || !isset($data['name']) || !is_array($data['name'])) {
+            return $data;
+        }
+
+        $files = $data;
+        foreach (self::$fileKeys as $k) {
+            unset($files[$k]);
+        }
+
+        foreach ($data['name'] as $key => $name) {
+            $files[$key] = $this->fixPhpFilesArray(array(
+                'error' => $data['error'][$key],
+                'name' => $name,
+                'type' => $data['type'][$key],
+                'tmp_name' => $data['tmp_name'][$key],
+                'size' => $data['size'][$key],
+            ));
+        }
+
+        return $files;
+    }
+}
diff --git a/core/lib/Drupal/Core/Http/ParameterBagWithBc.php b/core/lib/Drupal/Core/Http/ParameterBagWithBc.php
new file mode 100644
index 0000000000..37b4964525
--- /dev/null
+++ b/core/lib/Drupal/Core/Http/ParameterBagWithBc.php
@@ -0,0 +1,72 @@
+<?php
+
+namespace Drupal\Core\Http;
+
+use Symfony\Component\HttpFoundation\ParameterBag;
+
+class ParameterBagWithBc extends ParameterBag {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function get($key, $default = NULL, $deep = NULL) {
+    // We could do a couple of things:
+    // - throw an exception
+    // - trigger an error
+    // - trigger a deprecated warning
+    // - actually implement the function [x]
+    
+    if ($deep !== NULL) {
+      @trigger_error('Using paths to find deeper items in '.__METHOD__.' is deprecated since version 2.8 and will be removed in 3.0. Filter the returned value in your own code instead.', E_USER_DEPRECATED);
+    }
+    if ($deep) {
+      return $this->getDeep($key, $default);
+    }
+    return parent::get($key, $default);
+  }
+
+  protected function getDeep($key, $default = NULL) {
+    if (FALSE === $pos = strpos($key, '[')) {
+      return array_key_exists($key, $this->parameters) ? $this->parameters[$key] : $default;
+    }
+    $root = substr($key, 0, $pos);
+    if (!array_key_exists($root, $this->parameters)) {
+      return $default;
+    }
+    $value = $this->parameters[$root];
+    $currentKey = NULL;
+    for ($i = $pos, $c = strlen($key); $i < $c; ++$i) {
+      $char = $key[$i];
+      if ('[' === $char) {
+        if (NULL !== $currentKey) {
+          throw new \InvalidArgumentException(sprintf('Malformed path. Unexpected "[" at position %d.',
+            $i));
+        }
+        $currentKey = '';
+      }
+      elseif (']' === $char) {
+        if (NULL === $currentKey) {
+          throw new \InvalidArgumentException(sprintf('Malformed path. Unexpected "]" at position %d.',
+            $i));
+        }
+        if (!is_array($value) || !array_key_exists($currentKey, $value)) {
+          return $default;
+        }
+        $value = $value[$currentKey];
+        $currentKey = NULL;
+      }
+      else {
+        if (NULL === $currentKey) {
+          throw new \InvalidArgumentException(sprintf('Malformed path. Unexpected "%s" at position %d.',
+            $char, $i));
+        }
+        $currentKey .= $char;
+      }
+    }
+    if (NULL !== $currentKey) {
+      throw new \InvalidArgumentException('Malformed path. Path must end with "]".');
+    }
+    return $value;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Http/RequestWithBC.php b/core/lib/Drupal/Core/Http/RequestWithBC.php
new file mode 100644
index 0000000000..3d7ac7bb32
--- /dev/null
+++ b/core/lib/Drupal/Core/Http/RequestWithBC.php
@@ -0,0 +1,39 @@
+<?php
+
+namespace Drupal\Core\Http;
+
+use Symfony\Component\HttpFoundation\HeaderBag;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\ServerBag;
+
+/**
+ * Symfony 3.x broke the $deep parameter on request bags.
+ *
+ * Let's throw at least an exception if its passed along.
+ */
+class RequestWithBC extends Request {
+
+  public function initialize(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = NULL) {
+    $this->request = new ParameterBagWithBc($request);
+    $this->query = new ParameterBagWithBc($query);
+    $this->attributes = new ParameterBagWithBc($attributes);
+    $this->cookies = new ParameterBagWithBc($cookies);
+    $this->files = new FileBag($files);
+    $this->server = new ServerBag($server);
+    $this->headers = new HeaderBag($this->server->getHeaders());
+
+    $this->content = $content;
+    $this->languages = null;
+    $this->charsets = null;
+    $this->encodings = null;
+    $this->acceptableContentTypes = null;
+    $this->pathInfo = null;
+    $this->requestUri = null;
+    $this->baseUrl = null;
+    $this->basePath = null;
+    $this->method = null;
+    $this->format = null;
+  }
+
+
+}
diff --git a/core/lib/Drupal/Core/Http/TrustedHostsRequestFactory.php b/core/lib/Drupal/Core/Http/TrustedHostsRequestFactory.php
index 3aa0490f4f..676e860654 100644
--- a/core/lib/Drupal/Core/Http/TrustedHostsRequestFactory.php
+++ b/core/lib/Drupal/Core/Http/TrustedHostsRequestFactory.php
@@ -61,7 +61,7 @@ public function createRequest(array $query = [], array $request = [], array $att
     if (empty($server['HTTP_HOST']) || ($server['HTTP_HOST'] === 'localhost' && $this->host !== 'localhost')) {
       $server['HTTP_HOST'] = $this->host;
     }
-    return new Request($query, $request, $attributes, $cookies, $files, $server, $content);
+    return new RequestWithBC($query, $request, $attributes, $cookies, $files, $server, $content);
   }
 
 }
