diff --git a/app/code/Magento/Quote/Setup/ConvertSerializedDataToJson.php b/app/code/Magento/Quote/Setup/ConvertSerializedDataToJson.php
new file mode 100644
index 0000000000000000000000000000000000000000..7b3da6ba95c69a77b6661cfa562837a51a4aba83
--- /dev/null
+++ b/app/code/Magento/Quote/Setup/ConvertSerializedDataToJson.php
@@ -0,0 +1,140 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Quote\Setup;
+
+use Magento\Framework\DB\FieldDataConverterFactory;
+use Magento\Framework\DB\Select\QueryModifierFactory;
+use Magento\Framework\DB\Query\Generator;
+
+/**
+ * Convert serialized data in quote tables to JSON
+ */
+class ConvertSerializedDataToJson
+{
+    /**
+     * @var QuoteSetup
+     */
+    private $quoteSetup;
+
+    /**
+     * @var FieldDataConverterFactory
+     */
+    private $fieldDataConverterFactory;
+
+    /**
+     * @var QueryModifierFactory
+     */
+    private $queryModifierFactory;
+
+    /**
+     * @var Generator
+     */
+    private $queryGenerator;
+
+    /**
+     * Constructor
+     *
+     * @param QuoteSetup $quoteSetup
+     * @param FieldDataConverterFactory $fieldDataConverterFactory
+     * @param QueryModifierFactory $queryModifierFactory
+     * @param Generator $queryGenerator
+     */
+    public function __construct(
+        QuoteSetup $quoteSetup,
+        FieldDataConverterFactory $fieldDataConverterFactory,
+        QueryModifierFactory $queryModifierFactory,
+        Generator $queryGenerator
+    ) {
+        $this->quoteSetup = $quoteSetup;
+        $this->fieldDataConverterFactory = $fieldDataConverterFactory;
+        $this->queryModifierFactory = $queryModifierFactory;
+        $this->queryGenerator = $queryGenerator;
+    }
+
+    /**
+     * Convert data for additional_information field in quote_payment table from serialized
+     * to JSON format
+     *
+     * @return void
+     * @throws \InvalidArgumentException
+     */
+    public function convert()
+    {
+        $fieldDataConverter = $this->fieldDataConverterFactory->create(
+            \Magento\Framework\DB\DataConverter\SerializedToJson::class
+        );
+        $fieldDataConverter->convert(
+            $this->quoteSetup->getConnection(),
+            $this->quoteSetup->getTable('quote_payment'),
+            'payment_id',
+            'additional_information'
+        );
+        $fieldDataConverter->convert(
+            $this->quoteSetup->getConnection(),
+            $this->quoteSetup->getTable('quote_address'),
+            'address_id',
+            'applied_taxes'
+        );
+        $queryModifier = $this->queryModifierFactory->create(
+            'in',
+            [
+                'values' => [
+                    'code' => [
+                        'parameters',
+                        'info_buyRequest',
+                        'attributes',
+                        'bundle_option_ids',
+                        'bundle_selection_ids',
+                        'bundle_selection_attributes',
+                    ]
+                ]
+            ]
+        );
+        $fieldDataConverter->convert(
+            $this->quoteSetup->getConnection(),
+            $this->quoteSetup->getTable('quote_item_option'),
+            'option_id',
+            'value',
+            $queryModifier
+        );
+        $select = $this->quoteSetup->getSetup()
+            ->getConnection()
+            ->select()
+            ->from(
+                $this->quoteSetup->getSetup()
+                    ->getTable('catalog_product_option'),
+                ['option_id']
+            )
+            ->where('type = ?', 'file');
+        $iterator = $this->queryGenerator->generate('option_id', $select);
+        foreach ($iterator as $selectByRange) {
+            $codes = $this->quoteSetup->getSetup()
+                ->getConnection()
+                ->fetchCol($selectByRange);
+            $codes = array_map(
+                function ($id) {
+                    return 'option_' . $id;
+                },
+                $codes
+            );
+            $queryModifier = $this->queryModifierFactory->create(
+                'in',
+                [
+                    'values' => [
+                        'code' => $codes
+                    ]
+                ]
+            );
+            $fieldDataConverter->convert(
+                $this->quoteSetup->getConnection(),
+                $this->quoteSetup->getTable('quote_item_option'),
+                'option_id',
+                'value',
+                $queryModifier
+            );
+        }
+    }
+}
diff --git a/app/code/Magento/Quote/Setup/QuoteSetup.php b/app/code/Magento/Quote/Setup/QuoteSetup.php
index 1ef5f4b0dae2ee91a9580ae9097f6d129ce8f24e..cbd357d537fb12e2f42037a432d138012dfe446d 100644
--- a/app/code/Magento/Quote/Setup/QuoteSetup.php
+++ b/app/code/Magento/Quote/Setup/QuoteSetup.php
@@ -13,7 +13,8 @@ use Magento\Framework\App\Config\ScopeConfigInterface;
 use Magento\Framework\Setup\ModuleDataSetupInterface;
 
 /**
- * Setup Model of Quote Module
+ * Quote module setup class
+ *
  * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  * @codeCoverageIgnore
  */
@@ -75,9 +76,9 @@ class QuoteSetup extends EavSetup
      */
     protected function _flatTableExist($table)
     {
-        $tablesList = $this->getSetup()->getConnection(self::$connectionName)->listTables();
+        $tablesList = $this->getConnection()->listTables();
         return in_array(
-            strtoupper($this->getSetup()->getTable($table, self::$connectionName)),
+            strtoupper($this->getTable($table)),
             array_map('strtoupper', $tablesList)
         );
     }
@@ -115,15 +116,14 @@ class QuoteSetup extends EavSetup
      */
     protected function _addFlatAttribute($table, $attribute, $attr)
     {
-        $tableInfo = $this->getSetup()
-            ->getConnection(self::$connectionName)
-            ->describeTable($this->getSetup()->getTable($table, self::$connectionName));
+        $tableInfo = $this->getConnection()
+            ->describeTable($this->getTable($table));
         if (isset($tableInfo[$attribute])) {
             return $this;
         }
         $columnDefinition = $this->_getAttributeColumnDefinition($attribute, $attr);
-        $this->getSetup()->getConnection(self::$connectionName)->addColumn(
-            $this->getSetup()->getTable($table, self::$connectionName),
+        $this->getConnection()->addColumn(
+            $this->getTable($table),
             $attribute,
             $columnDefinition
         );
@@ -195,4 +195,25 @@ class QuoteSetup extends EavSetup
     {
         return $this->_encryptor;
     }
+
+    /**
+     * Get quote connection
+     *
+     * @return \Magento\Framework\DB\Adapter\AdapterInterface
+     */
+    public function getConnection()
+    {
+        return $this->getSetup()->getConnection(self::$connectionName);
+    }
+
+    /**
+     * Get table name
+     *
+     * @param string $table
+     * @return string
+     */
+    public function getTable($table)
+    {
+        return $this->getSetup()->getTable($table, self::$connectionName);
+    }
 }
diff --git a/app/code/Magento/Quote/Setup/UpgradeData.php b/app/code/Magento/Quote/Setup/UpgradeData.php
index 25e784be91ca301f2b18efaac1a743fb88f9d689..5b9e3482081cd24d358fd2fa165b87c8081c7f75 100644
--- a/app/code/Magento/Quote/Setup/UpgradeData.php
+++ b/app/code/Magento/Quote/Setup/UpgradeData.php
@@ -8,44 +8,31 @@ namespace Magento\Quote\Setup;
 use Magento\Framework\Setup\UpgradeDataInterface;
 use Magento\Framework\Setup\ModuleContextInterface;
 use Magento\Framework\Setup\ModuleDataSetupInterface;
-use Magento\Framework\DB\FieldDataConverterFactory;
-use Magento\Framework\DB\DataConverter\SerializedToJson;
-use Magento\Framework\DB\Select\QueryModifierFactory;
-use Magento\Framework\DB\Select\InQueryModifier;
-use Magento\Framework\DB\Query\Generator;
 
 class UpgradeData implements UpgradeDataInterface
 {
     /**
-     * @var FieldDataConverterFactory
+     * @var QuoteSetupFactory
      */
-    private $fieldDataConverterFactory;
+    private $quoteSetupFactory;
 
     /**
-     * @var QueryModifierFactory
+     * @var ConvertSerializedDataToJsonFactory
      */
-    private $queryModifierFactory;
-
-    /**
-     * @var Generator
-     */
-    private $queryGenerator;
+    private $convertSerializedDataToJsonFactory;
 
     /**
      * Constructor
      *
-     * @param FieldDataConverterFactory $fieldDataConverterFactory
-     * @param QueryModifierFactory $queryModifierFactory
-     * @param Generator $queryGenerator
+     * @param QuoteSetupFactory $quoteSetupFactory
+     * @param ConvertSerializedDataToJsonFactory $convertSerializedDataToJsonFactory
      */
     public function __construct(
-        FieldDataConverterFactory $fieldDataConverterFactory,
-        QueryModifierFactory $queryModifierFactory,
-        Generator $queryGenerator
+        QuoteSetupFactory $quoteSetupFactory,
+        ConvertSerializedDataToJsonFactory $convertSerializedDataToJsonFactory
     ) {
-        $this->fieldDataConverterFactory = $fieldDataConverterFactory;
-        $this->queryModifierFactory = $queryModifierFactory;
-        $this->queryGenerator = $queryGenerator;
+        $this->quoteSetupFactory = $quoteSetupFactory;
+        $this->convertSerializedDataToJsonFactory = $convertSerializedDataToJsonFactory;
     }
 
     /**
@@ -54,91 +41,9 @@ class UpgradeData implements UpgradeDataInterface
     public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
     {
         if (version_compare($context->getVersion(), '2.0.4', '<')) {
-            $this->upgradeToVersionTwoZeroFour($setup);
-        }
-    }
-
-    /**
-     * Upgrade to version 2.0.4, convert data for additional_information field in quote_payment table from serialized
-     * to JSON format
-     *
-     * @param ModuleDataSetupInterface $setup
-     * @return void
-     */
-    private function upgradeToVersionTwoZeroFour(ModuleDataSetupInterface $setup)
-    {
-        $fieldDataConverter = $this->fieldDataConverterFactory->create(SerializedToJson::class);
-        $fieldDataConverter->convert(
-            $setup->getConnection(),
-            $setup->getTable('quote_payment'),
-            'payment_id',
-            'additional_information'
-        );
-        $fieldDataConverter->convert(
-            $setup->getConnection(),
-            $setup->getTable('quote_address'),
-            'address_id',
-            'applied_taxes'
-        );
-        $fieldDataConverter->convert(
-            $setup->getConnection(),
-            $setup->getTable('quote_payment'),
-            'payment_id',
-            'additional_data'
-        );
-        $queryModifier = $this->queryModifierFactory->create(
-            InQueryModifier::class,
-            [
-                'values' => [
-                    'code' => [
-                        'parameters',
-                        'info_buyRequest',
-                        'bundle_option_ids',
-                        'bundle_selection_ids',
-                        'attributes',
-                        'bundle_selection_attributes',
-                    ]
-                ]
-            ]
-        );
-        $fieldDataConverter->convert(
-            $setup->getConnection(),
-            $setup->getTable('quote_item_option'),
-            'option_id',
-            'value',
-            $queryModifier
-        );
-        $select = $setup->getConnection()
-            ->select()
-            ->from(
-                $setup->getTable('catalog_product_option'),
-                ['option_id']
-            )
-            ->where('type = ?', 'file');
-        $iterator = $this->queryGenerator->generate('option_id', $select);
-        foreach ($iterator as $selectByRange) {
-            $codes = $setup->getConnection()->fetchCol($selectByRange);
-            $codes = array_map(
-                function ($id) {
-                    return 'option_' . $id;
-                },
-                $codes
-            );
-            $queryModifier = $this->queryModifierFactory->create(
-                InQueryModifier::class,
-                [
-                    'values' => [
-                        'code' => $codes
-                    ]
-                ]
-            );
-            $fieldDataConverter->convert(
-                $setup->getConnection(),
-                $setup->getTable('quote_item_option'),
-                'option_id',
-                'value',
-                $queryModifier
-            );
+            $quoteSetup = $this->quoteSetupFactory->create(['setup' => $setup]);
+            $this->convertSerializedDataToJsonFactory->create(['quoteSetup' => $quoteSetup])
+                ->convert();
         }
     }
 }
diff --git a/app/code/Magento/Sales/Setup/ConvertSerializedDataToJson.php b/app/code/Magento/Sales/Setup/ConvertSerializedDataToJson.php
new file mode 100644
index 0000000000000000000000000000000000000000..52047d0e59dc6ff6da8e3b435ba4355933ddc30a
--- /dev/null
+++ b/app/code/Magento/Sales/Setup/ConvertSerializedDataToJson.php
@@ -0,0 +1,87 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Setup;
+
+use Magento\Framework\DB\FieldDataConverterFactory;
+use Magento\Framework\DB\DataConverter\SerializedToJson;
+
+/**
+ *  Convert serialized data in sales tables to JSON
+ */
+class ConvertSerializedDataToJson
+{
+    /**
+     * @var SalesSetup
+     */
+    private $salesSetup;
+
+    /**
+     * @var FieldDataConverterFactory
+     */
+    private $fieldDataConverterFactory;
+
+    /**
+     * @var array
+     */
+    private $fieldsToUpdate = [
+        [
+            'table' => 'sales_order_item',
+            'identifier' => 'item_id',
+            'title' => 'product_options'
+        ],
+        [
+            'table' => 'sales_shipment',
+            'identifier' => 'entity_id',
+            'title' => 'packages'
+        ],
+        [
+            'table' => 'sales_order_payment',
+            'identifier' => 'entity_id',
+            'title' => 'additional_information'
+        ],
+        [
+            'table' => 'sales_payment_transaction',
+            'identifier' => 'transaction_id',
+            'title' => 'additional_information'
+        ]
+    ];
+
+    /**
+     * Constructor
+     *
+     * @param SalesSetup $salesSetup
+     * @param FieldDataConverterFactory $fieldDataConverterFactory
+     */
+    public function __construct(
+        SalesSetup $salesSetup,
+        FieldDataConverterFactory $fieldDataConverterFactory
+    ) {
+        $this->salesSetup = $salesSetup;
+        $this->fieldDataConverterFactory = $fieldDataConverterFactory;
+    }
+
+    /**
+     * Convert data for the following fields from serialized to JSON format:
+     * sales_order_item.product_options
+     * sales_shipment.packages
+     * sales_order_payment.additional_information
+     * sales_payment_transaction.additional_information
+     *
+     * @return void
+     */
+    public function convert()
+    {
+        $fieldDataConverter = $this->fieldDataConverterFactory->create(SerializedToJson::class);
+        foreach ($this->fieldsToUpdate as $field) {
+            $fieldDataConverter->convert(
+                $this->salesSetup->getConnection(),
+                $this->salesSetup->getTable($field['table']),
+                $field['identifier'],
+                $field['title']
+            );
+        }
+    }
+}
diff --git a/app/code/Magento/Sales/Setup/SalesSetup.php b/app/code/Magento/Sales/Setup/SalesSetup.php
index 3a2c999678a03e4115c867620092438cf27628b3..80b1ec4e8dc5fd2c171edc2e3ce8d5da8ebb9cff 100644
--- a/app/code/Magento/Sales/Setup/SalesSetup.php
+++ b/app/code/Magento/Sales/Setup/SalesSetup.php
@@ -11,13 +11,15 @@ use Magento\Framework\App\CacheInterface;
 use Magento\Framework\App\Config\ScopeConfigInterface;
 use Magento\Framework\Encryption\EncryptorInterface;
 use Magento\Framework\Setup\ModuleDataSetupInterface;
+use Magento\Eav\Setup\EavSetup;
 
 /**
- * Setup Model of Sales Module
- * @codeCoverageIgnore
+ * Sales module setup class
+ *
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ * @codeCoverageIgnore
  */
-class SalesSetup extends \Magento\Eav\Setup\EavSetup
+class SalesSetup extends EavSetup
 {
     /**
      * This should be set explicitly
@@ -55,6 +57,8 @@ class SalesSetup extends \Magento\Eav\Setup\EavSetup
     private static $connectionName = 'sales';
 
     /**
+     * Constructor
+     * 
      * @param ModuleDataSetupInterface $setup
      * @param Context $context
      * @param CacheInterface $cache
@@ -111,9 +115,10 @@ class SalesSetup extends \Magento\Eav\Setup\EavSetup
      */
     protected function _flatTableExist($table)
     {
-        $tablesList = $this->getSetup()->getConnection(self::$connectionName)->listTables();
+        $tablesList = $this->getConnection()
+            ->listTables();
         return in_array(
-            strtoupper($this->getSetup()->getTable($table, self::$connectionName)),
+            strtoupper($this->getTable($table)),
             array_map('strtoupper', $tablesList)
         );
     }
@@ -152,15 +157,14 @@ class SalesSetup extends \Magento\Eav\Setup\EavSetup
      */
     protected function _addFlatAttribute($table, $attribute, $attr)
     {
-        $tableInfo = $this->getSetup()
-            ->getConnection(self::$connectionName)
-            ->describeTable($this->getSetup()->getTable($table, self::$connectionName));
+        $tableInfo = $this->getConnection()
+            ->describeTable($this->getTable($table));
         if (isset($tableInfo[$attribute])) {
             return $this;
         }
         $columnDefinition = $this->_getAttributeColumnDefinition($attribute, $attr);
-        $this->getSetup()->getConnection(self::$connectionName)->addColumn(
-            $this->getSetup()->getTable($table, self::$connectionName),
+        $this->getConnection()->addColumn(
+            $this->getTable($table),
             $attribute,
             $columnDefinition
         );
@@ -180,8 +184,8 @@ class SalesSetup extends \Magento\Eav\Setup\EavSetup
     {
         if (in_array($entityTypeId, $this->_flatEntitiesGrid) && !empty($attr['grid'])) {
             $columnDefinition = $this->_getAttributeColumnDefinition($attribute, $attr);
-            $this->getSetup()->getConnection(self::$connectionName)->addColumn(
-                $this->getSetup()->getTable($table . '_grid', self::$connectionName),
+            $this->getConnection()->addColumn(
+                $this->getTable($table . '_grid'),
                 $attribute,
                 $columnDefinition
             );
@@ -297,4 +301,25 @@ class SalesSetup extends \Magento\Eav\Setup\EavSetup
     {
         return $this->encryptor;
     }
+
+    /**
+     * Get sales connection
+     *
+     * @return \Magento\Framework\DB\Adapter\AdapterInterface
+     */
+    public function getConnection()
+    {
+        return $this->getSetup()->getConnection(self::$connectionName);
+    }
+
+    /**
+     * Get table name
+     *
+     * @param string $table
+     * @return string
+     */
+    public function getTable($table)
+    {
+        return $this->getSetup()->getTable($table, self::$connectionName);
+    }
 }
diff --git a/app/code/Magento/Sales/Setup/UpgradeData.php b/app/code/Magento/Sales/Setup/UpgradeData.php
index 9db92988c6cdf8b8fb8c0eb4811e89e291600674..67b43fee29d08b95d6a6ca5c2f8465cadc83f4ed 100644
--- a/app/code/Magento/Sales/Setup/UpgradeData.php
+++ b/app/code/Magento/Sales/Setup/UpgradeData.php
@@ -6,9 +6,7 @@
 namespace Magento\Sales\Setup;
 
 /**
- * Class UpgradeData
- * @package Magento\Sales\Setup
- * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ * Data upgrade script
  */
 class UpgradeData implements \Magento\Framework\Setup\UpgradeDataInterface
 {
@@ -25,25 +23,25 @@ class UpgradeData implements \Magento\Framework\Setup\UpgradeDataInterface
     private $eavConfig;
 
     /**
-     * @var \Magento\Framework\DB\FieldDataConverterFactory
+     * @var \Magento\Sales\Setup\ConvertSerializedDataToJsonFactory
      */
-    private $fieldDataConverterFactory;
+    private $convertSerializedDataToJsonFactory;
 
     /**
      * Constructor
      *
      * @param \Magento\Sales\Setup\SalesSetupFactory $salesSetupFactory
+     * @param \Magento\Sales\Setup\ConvertSerializedDataToJsonFactory $convertSerializedDataToJsonFactory
      * @param \Magento\Eav\Model\Config $eavConfig
-     * @param \Magento\Framework\DB\FieldDataConverterFactory $fieldDataConverterFactory
      */
     public function __construct(
         \Magento\Sales\Setup\SalesSetupFactory $salesSetupFactory,
-        \Magento\Eav\Model\Config $eavConfig,
-        \Magento\Framework\DB\FieldDataConverterFactory $fieldDataConverterFactory
+        \Magento\Sales\Setup\ConvertSerializedDataToJsonFactory $convertSerializedDataToJsonFactory,
+        \Magento\Eav\Model\Config $eavConfig
     ) {
         $this->salesSetupFactory = $salesSetupFactory;
+        $this->convertSerializedDataToJsonFactory = $convertSerializedDataToJsonFactory;
         $this->eavConfig = $eavConfig;
-        $this->fieldDataConverterFactory = $fieldDataConverterFactory;
     }
 
     /**
@@ -58,7 +56,8 @@ class UpgradeData implements \Magento\Framework\Setup\UpgradeDataInterface
             $this->upgradeToTwoZeroOne($salesSetup);
         }
         if (version_compare($context->getVersion(), '2.0.5', '<')) {
-            $this->upgradeToVersionTwoZeroFive($setup);
+            $this->convertSerializedDataToJsonFactory->create(['salesSetup' => $salesSetup])
+                ->convert();
         }
         $this->eavConfig->clear();
     }
@@ -112,48 +111,4 @@ class UpgradeData implements \Magento\Framework\Setup\UpgradeDataInterface
             \Magento\Eav\Model\Entity\Increment\NumericValue::class
         );
     }
-
-    /**
-     * Upgrade to version 2.0.5, convert data for the following fields from serialized to JSON format:
-     * sales_order_item.product_options
-     * sales_shipment.packages
-     * sales_order_payment.additional_information
-     * sales_payment_transaction.additional_information
-     *
-     * @param \Magento\Framework\Setup\ModuleDataSetupInterface $setup
-     * @return void
-     */
-    private function upgradeToVersionTwoZeroFive(\Magento\Framework\Setup\ModuleDataSetupInterface $setup)
-    {
-        $productOptionsDataConverter = $this->fieldDataConverterFactory->create(
-            \Magento\Sales\Setup\SerializedDataConverter::class
-        );
-        $productOptionsDataConverter->convert(
-            $setup->getConnection(),
-            $setup->getTable('sales_order_item'),
-            'item_id',
-            'product_options'
-        );
-        $fieldDataConverter = $this->fieldDataConverterFactory->create(
-            \Magento\Framework\DB\DataConverter\SerializedToJson::class
-        );
-        $fieldDataConverter->convert(
-            $setup->getConnection(),
-            $setup->getTable('sales_shipment'),
-            'entity_id',
-            'packages'
-        );
-        $fieldDataConverter->convert(
-            $setup->getConnection(),
-            $setup->getTable('sales_order_payment'),
-            'entity_id',
-            'additional_information'
-        );
-        $fieldDataConverter->convert(
-            $setup->getConnection(),
-            $setup->getTable('sales_payment_transaction'),
-            'transaction_id',
-            'additional_information'
-        );
-    }
 }
diff --git a/app/etc/di.xml b/app/etc/di.xml
index 1b347574f4b2a2d3f010cb9a712da6cd6c7dbec2..5e58d5887678d91fdcfcccc1f28f751fa3502177 100755
--- a/app/etc/di.xml
+++ b/app/etc/di.xml
@@ -1214,4 +1214,11 @@
             </argument>
         </arguments>
     </type>
+    <type name="Magento\Framework\DB\Select\QueryModifierFactory">
+        <arguments>
+            <argument name="queryModifiers" xsi:type="array">
+                <item name="in" xsi:type="string">Magento\Framework\DB\Select\InQueryModifier</item>
+            </argument>
+        </arguments>
+    </type>
 </config>
diff --git a/lib/internal/Magento/Framework/DB/Select/InQueryModifier.php b/lib/internal/Magento/Framework/DB/Select/InQueryModifier.php
index cf20152d8043e7ce23b5e47f8699e0c45de99dfb..e8a03f709568a67c2e34ca07b923c3ffbf16dafb 100644
--- a/lib/internal/Magento/Framework/DB/Select/InQueryModifier.php
+++ b/lib/internal/Magento/Framework/DB/Select/InQueryModifier.php
@@ -8,7 +8,7 @@ namespace Magento\Framework\DB\Select;
 use Magento\Framework\DB\Select;
 
 /**
- * Add in condition to select
+ * Add IN condition to select
  */
 class InQueryModifier implements QueryModifierInterface
 {
diff --git a/lib/internal/Magento/Framework/DB/Select/QueryModifierFactory.php b/lib/internal/Magento/Framework/DB/Select/QueryModifierFactory.php
index fe2933627d51f6e2e1069a9f3a990e654f5011f0..21eb484b43268b11373b1dcc9fbf726bdc0cf600 100644
--- a/lib/internal/Magento/Framework/DB/Select/QueryModifierFactory.php
+++ b/lib/internal/Magento/Framework/DB/Select/QueryModifierFactory.php
@@ -17,26 +17,44 @@ class QueryModifierFactory
      */
     private $objectManager;
 
+    /**
+     * @var array
+     */
+    private $queryModifiers;
+
     /**
      * Constructor
      *
      * @param ObjectManagerInterface $objectManager
+     * @param array $queryModifiers
      */
     public function __construct(
-        ObjectManagerInterface $objectManager
+        ObjectManagerInterface $objectManager,
+        array $queryModifiers = []
     ) {
         $this->objectManager = $objectManager;
+        $this->queryModifiers = $queryModifiers;
     }
 
     /**
      * Create instance of QueryModifierInterface
      *
-     * @param string $queryModifierClassName
+     * @param string $type
      * @param array $data
      * @return QueryModifierInterface
+     * @throws \InvalidArgumentException
      */
-    public function create($queryModifierClassName, $data)
+    public function create($type, array $data = [])
     {
-        return $this->objectManager->create($queryModifierClassName, $data);
+        if (!isset($this->queryModifiers[$type])) {
+            throw new \InvalidArgumentException('Unknown query modifier type ' . $type);
+        }
+        $queryModifier = $this->objectManager->create($this->queryModifiers[$type], $data);
+        if (!($queryModifier instanceof QueryModifierInterface)) {
+            throw new \InvalidArgumentException(
+                $this->queryModifiers[$type] . ' must implement ' . QueryModifierInterface::class
+            );
+        }
+        return $queryModifier;
     }
 }
diff --git a/lib/internal/Magento/Framework/DB/Test/Unit/Select/QueryModifierFactoryTest.php b/lib/internal/Magento/Framework/DB/Test/Unit/Select/QueryModifierFactoryTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..b083b730bbdbaea4d36bb094eb47ca2361ae265b
--- /dev/null
+++ b/lib/internal/Magento/Framework/DB/Test/Unit/Select/QueryModifierFactoryTest.php
@@ -0,0 +1,106 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\DB\Test\Unit\Select;
+
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+use Magento\Framework\DB\Select\QueryModifierFactory;
+use Magento\Framework\DB\Select\InQueryModifier;
+use Magento\Framework\ObjectManagerInterface;
+
+class QueryModifierFactoryTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var ObjectManager
+     */
+    private $objectManager;
+
+    /**
+     * @var QueryModifierFactory
+     */
+    private $queryModifierFactory;
+
+    /**
+     * @var ObjectManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $objectManagerMock;
+
+    /**
+     * @var InQueryModifier|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $inQueryModifierMock;
+
+    protected function setUp()
+    {
+        $this->objectManager = new ObjectManager($this);
+        $this->objectManagerMock = $this->getMock(ObjectManagerInterface::class);
+        $this->inQueryModifierMock = $this->getMock(InQueryModifier::class, [], [], '', false);
+    }
+
+    public function testCreate()
+    {
+        $params = ['foo' => 'bar'];
+        $this->queryModifierFactory = $this->objectManager->getObject(
+            QueryModifierFactory::class,
+            [
+                'objectManager' => $this->objectManagerMock,
+                'queryModifiers' => [
+                    'in' => InQueryModifier::class
+                ]
+            ]
+        );
+        $this->objectManagerMock->expects($this->once())
+            ->method('create')
+            ->with(
+                InQueryModifier::class,
+                $params
+            )
+            ->willReturn($this->inQueryModifierMock);
+        $this->queryModifierFactory->create('in', $params);
+    }
+
+    /**
+     * @expectedException \InvalidArgumentException
+     */
+    public function testCreateUnknownQueryModifierType()
+    {
+        $params = ['foo' => 'bar'];
+        $this->queryModifierFactory = $this->objectManager->getObject(
+            QueryModifierFactory::class,
+            [
+                'objectManager' => $this->objectManagerMock,
+                'queryModifiers' => []
+            ]
+        );
+        $this->objectManagerMock->expects($this->never())
+            ->method('create');
+        $this->queryModifierFactory->create('in', $params);
+    }
+
+    /**
+     * @expectedException \InvalidArgumentException
+     */
+    public function testCreateDoesNotImplementInterface()
+    {
+        $params = ['foo' => 'bar'];
+        $this->queryModifierFactory = $this->objectManager->getObject(
+            QueryModifierFactory::class,
+            [
+                'objectManager' => $this->objectManagerMock,
+                'queryModifiers' => [
+                    'in' => \stdClass::class
+                ]
+            ]
+        );
+        $this->objectManagerMock->expects($this->once())
+            ->method('create')
+            ->with(
+                \stdClass::class,
+                $params
+            )
+            ->willReturn(new \stdClass());
+        $this->queryModifierFactory->create('in', $params);
+    }
+}