diff --git a/module/VuFind/config/module.config.php b/module/VuFind/config/module.config.php
index ad856e33f7b31373aec01861b1fe7477b3a4d212..228d6116212a18a342a605021eae18f70f3a0e07 100644
--- a/module/VuFind/config/module.config.php
+++ b/module/VuFind/config/module.config.php
@@ -468,24 +468,7 @@ $config = [
                     'guardian' => 'VuFind\Content\Reviews\Guardian',
                 ],
             ],
-            'db_row' => [
-                'factories' => [
-                    'changetracker' => 'VuFind\Db\Row\Factory::getChangeTracker',
-                    'comments' => 'VuFind\Db\Row\Factory::getComments',
-                    'externalsession' => 'VuFind\Db\Row\Factory::getExternalSession',
-                    'oairesumption' => 'VuFind\Db\Row\Factory::getOaiResumption',
-                    'record' => 'VuFind\Db\Row\Factory::getRecord',
-                    'resource' => 'VuFind\Db\Row\Factory::getResource',
-                    'resourcetags' => 'VuFind\Db\Row\Factory::getResourceTags',
-                    'search' => 'VuFind\Db\Row\Factory::getSearch',
-                    'session' => 'VuFind\Db\Row\Factory::getSession',
-                    'tags' => 'VuFind\Db\Row\Factory::getTags',
-                    'user' => 'VuFind\Db\Row\Factory::getUser',
-                    'usercard' => 'VuFind\Db\Row\Factory::getUserCard',
-                    'userlist' => 'VuFind\Db\Row\Factory::getUserList',
-                    'userresource' => 'VuFind\Db\Row\Factory::getUserResource',
-                ],
-            ],
+            'db_row' => [ /* see VuFind\Db\Row\PluginManager for defaults */ ],
             'db_table' => [
                 'abstract_factories' => ['VuFind\Db\Table\PluginFactory'],
                 'factories' => [
diff --git a/module/VuFind/src/VuFind/Db/Row/Factory.php b/module/VuFind/src/VuFind/Db/Row/Factory.php
deleted file mode 100644
index c3cdcd13f3774f295c4b0b8360b6254fb7086885..0000000000000000000000000000000000000000
--- a/module/VuFind/src/VuFind/Db/Row/Factory.php
+++ /dev/null
@@ -1,118 +0,0 @@
-<?php
-/**
- * Factory for DB rows.
- *
- * PHP version 5
- *
- * Copyright (C) Villanova University 2014.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * @category VuFind
- * @package  Db_Table
- * @author   Demian Katz <demian.katz@villanova.edu>
- * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
- * @link     https://vufind.org/wiki/development Wiki
- */
-namespace VuFind\Db\Row;
-
-use Zend\ServiceManager\ServiceManager;
-
-/**
- * Factory for DB tables.
- *
- * @category VuFind
- * @package  Db_Table
- * @author   Demian Katz <demian.katz@villanova.edu>
- * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
- * @link     https://vufind.org/wiki/development Wiki
- *
- * @codeCoverageIgnore
- */
-class Factory
-{
-    /**
-     * Construct a generic row object.
-     *
-     * @param string         $name Name of row to construct (fully qualified
-     * class name, or else a class name within the current namespace)
-     * @param ServiceManager $sm   Service manager
-     * @param array          $args Extra constructor arguments for row object
-     *
-     * @return object
-     */
-    public static function getGenericRow($name, ServiceManager $sm, $args = [])
-    {
-        // Prepend the current namespace unless we receive a FQCN:
-        $class = (strpos($name, '\\') === false)
-            ? __NAMESPACE__ . '\\' . $name : $name;
-        if (!class_exists($class)) {
-            throw new \Exception('Cannot construct ' . $class);
-        }
-        $adapter = $sm->get('VuFind\DbAdapter');
-        return new $class($adapter, ...$args);
-    }
-
-    /**
-     * Default factory behavior.
-     *
-     * @param string $name Method name being called
-     * @param array  $args Method arguments
-     *
-     * @return object
-     */
-    public static function __callStatic($name, $args)
-    {
-        // Strip "get" off method name, and use the remainder as the table name;
-        // grab the first argument to pass through as the service manager.
-        return static::getGenericRow(substr($name, 3), array_shift($args));
-    }
-
-    /**
-     * Construct the User row prototype.
-     *
-     * @param ServiceManager $sm Service manager.
-     *
-     * @return User
-     */
-    public static function getUser(ServiceManager $sm)
-    {
-        $config = $sm->get('VuFind\Config')->get('config');
-        $privacy = isset($config->Authentication->privacy)
-            && $config->Authentication->privacy;
-        $rowClass = $privacy ? 'PrivateUser' : 'User';
-        $prototype = static::getGenericRow($rowClass, $sm);
-        $prototype->setConfig($config);
-        if ($privacy) {
-            $sessionManager = $sm->get('VuFind\SessionManager');
-            $session = new \Zend\Session\Container('Account', $sessionManager);
-            $prototype->setSession($session);
-        }
-        return $prototype;
-    }
-
-    /**
-     * Construct the UserList row prototype.
-     *
-     * @param ServiceManager $sm Service manager.
-     *
-     * @return UserList
-     */
-    public static function getUserList(ServiceManager $sm)
-    {
-        $sessionManager = $sm->get('VuFind\SessionManager');
-        $session = new \Zend\Session\Container('List', $sessionManager);
-        return static::getGenericRow('UserList', $sm, [$session]);
-    }
-}
diff --git a/module/VuFind/src/VuFind/Db/Row/PluginManager.php b/module/VuFind/src/VuFind/Db/Row/PluginManager.php
index b3e8b0da52b5bb6a96ad4cbe3b6f82518c65c425..3fb8013643f4de32626685872e98dcf99dc829e4 100644
--- a/module/VuFind/src/VuFind/Db/Row/PluginManager.php
+++ b/module/VuFind/src/VuFind/Db/Row/PluginManager.php
@@ -38,6 +38,50 @@ namespace VuFind\Db\Row;
  */
 class PluginManager extends \VuFind\ServiceManager\AbstractPluginManager
 {
+    /**
+     * Default plugin aliases.
+     *
+     * @var array
+     */
+    protected $aliases = [
+        'changetracker' => 'VuFind\Db\Row\ChangeTracker',
+        'comments' => 'VuFind\Db\Row\Comments',
+        'externalsession' => 'VuFind\Db\Row\ExternalSession',
+        'oairesumption' => 'VuFind\Db\Row\OaiResumption',
+        'record' => 'VuFind\Db\Row\Record',
+        'resource' => 'VuFind\Db\Row\Resource',
+        'resourcetags' => 'VuFind\Db\Row\ResourceTags',
+        'search' => 'VuFind\Db\Row\Search',
+        'session' => 'VuFind\Db\Row\Session',
+        'tags' => 'VuFind\Db\Row\Tags',
+        'user' => 'VuFind\Db\Row\User',
+        'usercard' => 'VuFind\Db\Row\UserCard',
+        'userlist' => 'VuFind\Db\Row\UserList',
+        'userresource' => 'VuFind\Db\Row\UserResource',
+    ];
+
+    /**
+     * Default plugin factories.
+     *
+     * @var array
+     */
+    protected $factories = [
+        'VuFind\Db\Row\ChangeTracker' => 'VuFind\Db\Row\RowGatewayFactory',
+        'VuFind\Db\Row\Comments' => 'VuFind\Db\Row\RowGatewayFactory',
+        'VuFind\Db\Row\ExternalSession' => 'VuFind\Db\Row\RowGatewayFactory',
+        'VuFind\Db\Row\OaiResumption' => 'VuFind\Db\Row\RowGatewayFactory',
+        'VuFind\Db\Row\Record' => 'VuFind\Db\Row\RowGatewayFactory',
+        'VuFind\Db\Row\Resource' => 'VuFind\Db\Row\RowGatewayFactory',
+        'VuFind\Db\Row\ResourceTags' => 'VuFind\Db\Row\RowGatewayFactory',
+        'VuFind\Db\Row\Search' => 'VuFind\Db\Row\RowGatewayFactory',
+        'VuFind\Db\Row\Session' => 'VuFind\Db\Row\RowGatewayFactory',
+        'VuFind\Db\Row\Tags' => 'VuFind\Db\Row\RowGatewayFactory',
+        'VuFind\Db\Row\User' => 'VuFind\Db\Row\UserFactory',
+        'VuFind\Db\Row\UserCard' => 'VuFind\Db\Row\RowGatewayFactory',
+        'VuFind\Db\Row\UserList' => 'VuFind\Db\Row\UserListFactory',
+        'VuFind\Db\Row\UserResource' => 'VuFind\Db\Row\RowGatewayFactory',
+    ];
+
     /**
      * Return the name of the base class or interface that plug-ins must conform
      * to.
diff --git a/module/VuFind/src/VuFind/Db/Row/RowGatewayFactory.php b/module/VuFind/src/VuFind/Db/Row/RowGatewayFactory.php
new file mode 100644
index 0000000000000000000000000000000000000000..c1c8d15290e76ce6acb5f6d69cdeddcaad5f7f46
--- /dev/null
+++ b/module/VuFind/src/VuFind/Db/Row/RowGatewayFactory.php
@@ -0,0 +1,63 @@
+<?php
+/**
+ * Generic row gateway factory.
+ *
+ * PHP version 5
+ *
+ * Copyright (C) Villanova University 2017.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category VuFind
+ * @package  Db_Row
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     https://vufind.org/wiki/development Wiki
+ */
+namespace VuFind\Db\Row;
+
+use Interop\Container\ContainerInterface;
+
+/**
+ * Generic row gateway factory.
+ *
+ * @category VuFind
+ * @package  Db_Row
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     https://vufind.org/wiki/development Wiki
+ */
+class RowGatewayFactory implements \Zend\ServiceManager\Factory\FactoryInterface
+{
+    /**
+     * Create an object
+     *
+     * @param ContainerInterface $container     Service manager
+     * @param string             $requestedName Service being created
+     * @param null|array         $options       Extra options (optional)
+     *
+     * @return object
+     *
+     * @throws ServiceNotFoundException if unable to resolve the service.
+     * @throws ServiceNotCreatedException if an exception is raised when
+     * creating a service.
+     * @throws ContainerException if any other error occurs
+     */
+    public function __invoke(ContainerInterface $container, $requestedName,
+        array $options = null
+    ) {
+        $adapter = $container->get('VuFind\DbAdapter');
+        return new $requestedName($adapter, ...($options !== null ? $options : []));
+    }
+}
diff --git a/module/VuFind/src/VuFind/Db/Row/UserFactory.php b/module/VuFind/src/VuFind/Db/Row/UserFactory.php
new file mode 100644
index 0000000000000000000000000000000000000000..98ad8a0b5add97abd8db1d0f1cbf0ea8bcc6bce8
--- /dev/null
+++ b/module/VuFind/src/VuFind/Db/Row/UserFactory.php
@@ -0,0 +1,83 @@
+<?php
+/**
+ * User row gateway factory.
+ *
+ * PHP version 5
+ *
+ * Copyright (C) Villanova University 2017.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category VuFind
+ * @package  Db_Row
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     https://vufind.org/wiki/development Wiki
+ */
+namespace VuFind\Db\Row;
+
+use Interop\Container\ContainerInterface;
+
+/**
+ * User row gateway factory.
+ *
+ * @category VuFind
+ * @package  Db_Row
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     https://vufind.org/wiki/development Wiki
+ */
+class UserFactory extends RowGatewayFactory
+{
+    /**
+     * Class name for private user class.
+     *
+     * @var string
+     */
+    protected $privateUserClass = __NAMESPACE__ . '\PrivateUser';
+
+    /**
+     * Create an object
+     *
+     * @param ContainerInterface $container     Service manager
+     * @param string             $requestedName Service being created
+     * @param null|array         $options       Extra options (optional)
+     *
+     * @return object
+     *
+     * @throws ServiceNotFoundException if unable to resolve the service.
+     * @throws ServiceNotCreatedException if an exception is raised when
+     * creating a service.
+     * @throws ContainerException if any other error occurs
+     */
+    public function __invoke(ContainerInterface $container, $requestedName,
+        array $options = null
+    ) {
+        if (!empty($options)) {
+            throw new \Exception('Unexpected options sent to factory!');
+        }
+        $config = $container->get('VuFind\Config')->get('config');
+        $privacy = isset($config->Authentication->privacy)
+            && $config->Authentication->privacy;
+        $rowClass = $privacy ? $this->privateUserClass : $requestedName;
+        $prototype = parent::__invoke($container, $rowClass, $options);
+        $prototype->setConfig($config);
+        if ($privacy) {
+            $sessionManager = $container->get('VuFind\SessionManager');
+            $session = new \Zend\Session\Container('Account', $sessionManager);
+            $prototype->setSession($session);
+        }
+        return $prototype;
+    }
+}
diff --git a/module/VuFind/src/VuFind/Db/Row/UserListFactory.php b/module/VuFind/src/VuFind/Db/Row/UserListFactory.php
new file mode 100644
index 0000000000000000000000000000000000000000..95a34d80db4356d4e7ca2e65ad738fd0a5a0ba5e
--- /dev/null
+++ b/module/VuFind/src/VuFind/Db/Row/UserListFactory.php
@@ -0,0 +1,67 @@
+<?php
+/**
+ * UserList row gateway factory.
+ *
+ * PHP version 5
+ *
+ * Copyright (C) Villanova University 2017.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category VuFind
+ * @package  Db_Row
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     https://vufind.org/wiki/development Wiki
+ */
+namespace VuFind\Db\Row;
+
+use Interop\Container\ContainerInterface;
+
+/**
+ * UserList row gateway factory.
+ *
+ * @category VuFind
+ * @package  Db_Row
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     https://vufind.org/wiki/development Wiki
+ */
+class UserListFactory extends RowGatewayFactory
+{
+    /**
+     * Create an object
+     *
+     * @param ContainerInterface $container     Service manager
+     * @param string             $requestedName Service being created
+     * @param null|array         $options       Extra options (optional)
+     *
+     * @return object
+     *
+     * @throws ServiceNotFoundException if unable to resolve the service.
+     * @throws ServiceNotCreatedException if an exception is raised when
+     * creating a service.
+     * @throws ContainerException if any other error occurs
+     */
+    public function __invoke(ContainerInterface $container, $requestedName,
+        array $options = null
+    ) {
+        if (!empty($options)) {
+            throw new \Exception('Unexpected options sent to factory!');
+        }
+        $sessionManager = $container->get('VuFind\SessionManager');
+        $session = new \Zend\Session\Container('List', $sessionManager);
+        return parent::__invoke($container, $requestedName, [$session]);
+    }
+}
diff --git a/module/VuFind/src/VuFindTest/Unit/DbTestCase.php b/module/VuFind/src/VuFindTest/Unit/DbTestCase.php
index 261286b876e451560546a3d34383f9be369f4af6..1c220362e41a939f39788a7fb826dde931eec1be 100644
--- a/module/VuFind/src/VuFindTest/Unit/DbTestCase.php
+++ b/module/VuFind/src/VuFindTest/Unit/DbTestCase.php
@@ -90,28 +90,7 @@ abstract class DbTestCase extends TestCase
      */
     protected function addRowManager(ServiceManager $sm)
     {
-        $factory = new \VuFind\Db\Row\PluginManager(
-            $sm,
-            [
-                'factories' => [
-                    'changetracker' => 'VuFind\Db\Row\Factory::getChangeTracker',
-                    'comments' => 'VuFind\Db\Row\Factory::getComments',
-                    'externalsession' =>
-                        'VuFind\Db\Row\Factory::getExternalSession',
-                    'oairesumption' => 'VuFind\Db\Row\Factory::getOaiResumption',
-                    'record' => 'VuFind\Db\Row\Factory::getRecord',
-                    'resource' => 'VuFind\Db\Row\Factory::getResource',
-                    'resourcetags' => 'VuFind\Db\Row\Factory::getResourceTags',
-                    'search' => 'VuFind\Db\Row\Factory::getSearch',
-                    'session' => 'VuFind\Db\Row\Factory::getSession',
-                    'tags' => 'VuFind\Db\Row\Factory::getTags',
-                    'user' => 'VuFind\Db\Row\Factory::getUser',
-                    'usercard' => 'VuFind\Db\Row\Factory::getUserCard',
-                    'userlist' => 'VuFind\Db\Row\Factory::getUserList',
-                    'userresource' => 'VuFind\Db\Row\Factory::getUserResource',
-                ],
-            ]
-        );
+        $factory = new \VuFind\Db\Row\PluginManager($sm);
         $sm->setService('VuFind\DbRowPluginManager', $factory);
     }