diff --git a/fid/config/vufind/fid.ini b/fid/config/vufind/fid.ini
index 607d62d8f4ff16c449a9cf065627c12781c47e43..eb88b4d09e067a4b1c649de383387d79c19ca542 100644
--- a/fid/config/vufind/fid.ini
+++ b/fid/config/vufind/fid.ini
@@ -8,10 +8,8 @@ access_levels[] = full_access
 [UserProfile]
 role_display[] = "full_access"
 role_display[] = "limited_access"
-role_display[] = "read_user_list"
-role_display[] = "edit_user"
 role_display_priority[] = "full_access>limited_access"
-role_display_order = "full_access>limited_access>read_user_list>edit_user"
+role_display_order = "full_access>limited_access"
 
 [Admin]
 ; Whitelist of all fields that admins shall be able
@@ -27,7 +25,5 @@ overview_fields[] = 'Lastname'
 overview_fields[] = 'Permissions'
 
 ; List of all available user permissions
-permission_options[] = 'edit_user'
-permission_options[] = 'read_user_list'
 permission_options[] = 'limited_access'
 permission_options[] = 'full_access'
\ No newline at end of file
diff --git a/module/fid/config/address-collection.php b/module/fid/config/address-collection.php
index 09b669c9236b13721745ef27ee42355cc499a623..f94da88e9273a485df4c20b83a5601a7c7b57959 100644
--- a/module/fid/config/address-collection.php
+++ b/module/fid/config/address-collection.php
@@ -19,68 +19,191 @@
  * @license http://opensource.org/licenses/gpl-2.0.php GNU GPLv2
  */
 
-use Zend\Form\Element\Collection;
+use fid\InputFilter\RootAwareBaseInputFilter;
+use Zend\Filter\StringTrim;
 use Zend\Form\Element\Hidden;
 use Zend\Form\Element\Text;
 use Zend\Form\Fieldset;
+use Zend\Form\InputFilterProviderFieldset;
+use Zend\Validator\NotEmpty;
+use Zend\Validator\StringLength;
 
 return [
     'spec' => [
-        'name'    => 'addresses',
-        'type'    => Collection::class,
-        'options' => [
-            'count'          => 0,
-            'target_element' => [
-                'type'     => Fieldset::class,
-                'elements' => [
-                    'id' => [
-                        'spec' => [
-                            'name' => 'id',
-                            'type' => Hidden::class,
+        'name'     => 'addresses',
+        'type'     => Fieldset::class,
+        'elements' => [
+            'address_0' => [
+                'spec' => [
+                    'name'     => 0,
+                    'type'     => InputFilterProviderFieldset::class,
+                    'elements' => [
+                        'id'      => [
+                            'spec' => [
+                                'name' => 'id',
+                                'type' => Hidden::class,
+                            ],
                         ],
-                    ],
-                    'line1'   => [
-                        'spec' => [
-                            'name'    => 'line1',
-                            'type'    => Text::class,
-                            'options' => [
-                                'label' => 'label_address_line_1',
-                            ]
+                        'line1'   => [
+                            'spec' => [
+                                'name'    => 'line1',
+                                'type'    => Text::class,
+                                'options' => [
+                                    'label' => 'label_address_0_line_1',
+                                ],
+                            ],
                         ],
-                    ],
-                    'line2'   => [
-                        'spec' => [
-                            'name'    => 'line2',
-                            'type'    => Text::class,
-                            'options' => [
-                                'label' => 'label_address_line_2',
-                            ]
+                        'line2'   => [
+                            'spec' => [
+                                'name'    => 'line2',
+                                'type'    => Text::class,
+                                'options' => [
+                                    'label' => 'label_address_0_line_2',
+                                ]
+                            ],
                         ],
-                    ],
-                    'zip'     => [
-                        'spec' => [
-                            'name'    => 'zip',
-                            'type'    => Text::class,
-                            'options' => [
-                                'label' => 'label_address_zip',
-                            ]
+                        'zip'     => [
+                            'spec' => [
+                                'name'    => 'zip',
+                                'type'    => Text::class,
+                                'options' => [
+                                    'label' => 'label_address_0_zip',
+                                ],
+                            ],
                         ],
-                    ],
-                    'city'    => [
-                        'spec' => [
-                            'name'    => 'city',
-                            'type'    => Text::class,
-                            'options' => [
-                                'label' => 'label_address_city',
-                            ]
+                        'city'    => [
+                            'spec' => [
+                                'name'    => 'city',
+                                'type'    => Text::class,
+                                'options' => [
+                                    'label' => 'label_address_0_city',
+                                ],
+                            ],
+                        ],
+                        'country' => [
+                            'spec' => [
+                                'name'    => 'country',
+                                'type'    => Text::class,
+                                'options' => [
+                                    'label' => 'label_address_0_country',
+                                ],
+                            ],
                         ],
                     ],
-                    'country' => [
-                        'spec' => [
-                            'name'    => 'country',
-                            'type'    => Text::class,
-                            'options' => [
-                                'label' => 'label_address_country',
+                    'options'  => [
+                        'template'          => 'address-fieldset.phtml',
+                        'label'             => 'label_address_0',
+                        'input_filter_spec' => [
+                            'type' => RootAwareBaseInputFilter::class,
+                            'line1'   => [
+                                'name'       => 'line1',
+                                'filters'    => [
+                                    StringTrim::class => [
+                                        'name' => StringTrim::class,
+                                    ],
+                                ],
+                                'validators' => [
+                                    NotEmpty::class         => [
+                                        'name'    => NotEmpty::class,
+                                        'options' => [
+                                            'type' => NotEmpty::NULL,
+                                        ],
+                                    ],
+                                    StringLength::class     => [
+                                        'name'    => StringLength::class,
+                                        'options' => [
+                                            'max' => 255
+                                        ]
+                                    ],
+                                ],
+                            ],
+                            'line2'   => [
+                                'name'       => 'line2',
+                                'filters'    => [
+                                    StringTrim::class => [
+                                        'name' => StringTrim::class,
+                                    ],
+                                ],
+                                'validators' => [
+                                    NotEmpty::class     => [
+                                        'name'    => NotEmpty::class,
+                                        'options' => [
+                                            'type' => NotEmpty::NULL,
+                                        ],
+                                    ],
+                                    StringLength::class => [
+                                        'name'    => StringLength::class,
+                                        'options' => [
+                                            'max' => 255
+                                        ]
+                                    ],
+                                ],
+                            ],
+                            'zip'     => [
+                                'name'       => 'zip',
+                                'filters'    => [
+                                    StringTrim::class => [
+                                        'name' => StringTrim::class,
+                                    ],
+                                ],
+                                'validators' => [
+                                    StringLength::class     => [
+                                        'name'    => StringLength::class,
+                                        'options' => [
+                                            'max' => 255
+                                        ]
+                                    ],
+                                    NotEmpty::class         => [
+                                        'name'    => NotEmpty::class,
+                                        'options' => [
+                                            'type' => NotEmpty::NULL,
+                                        ],
+                                    ],
+                                ],
+                            ],
+                            'city'    => [
+                                'name'       => 'city',
+                                'filters'    => [
+                                    StringTrim::class => [
+                                        'name' => StringTrim::class,
+                                    ],
+                                ],
+                                'validators' => [
+                                    StringLength::class     => [
+                                        'name'    => StringLength::class,
+                                        'options' => [
+                                            'max' => 255
+                                        ]
+                                    ],
+                                    NotEmpty::class         => [
+                                        'name'    => NotEmpty::class,
+                                        'options' => [
+                                            'type' => NotEmpty::NULL,
+                                        ],
+                                    ],
+                                ],
+                            ],
+                            'country' => [
+                                'name'       => 'country',
+                                'filters'    => [
+                                    StringTrim::class => [
+                                        'name' => StringTrim::class,
+                                    ],
+                                ],
+                                'validators' => [
+                                    StringLength::class     => [
+                                        'name'    => StringLength::class,
+                                        'options' => [
+                                            'max' => 255
+                                        ]
+                                    ],
+                                    NotEmpty::class         => [
+                                        'name'    => NotEmpty::class,
+                                        'options' => [
+                                            'type' => NotEmpty::NULL,
+                                        ],
+                                    ],
+                                ],
                             ],
                         ],
                     ],
diff --git a/module/fid/config/address-input-filter.php b/module/fid/config/address-input-filter.php
deleted file mode 100644
index 79fa72a8d8fa66ec837c8fc54cdaeb3553508da3..0000000000000000000000000000000000000000
--- a/module/fid/config/address-input-filter.php
+++ /dev/null
@@ -1,179 +0,0 @@
-<?php
-/**
- * Copyright (C) 2019 Leipzig University Library
- *
- * 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.
- *
- * @author  Sebastian Kehr <kehr@ub.uni-leipzig.de>
- * @license http://opensource.org/licenses/gpl-2.0.php GNU GPLv2
- */
-
-use fid\FormModel\AddressValidator;
-use Zend\Filter\StringTrim;
-use Zend\InputFilter\CollectionInputFilter;
-use Zend\Validator\Callback;
-use Zend\Validator\NotEmpty;
-use Zend\Validator\StringLength;
-
-return [
-    'name' => 'addresses',
-    'type'         => CollectionInputFilter::class,
-    'input_filter' => [
-        'line1'   => [
-            'name'       => 'line1',
-            'filters'    => [
-                StringTrim::class => [
-                    'name' => StringTrim::class,
-                ],
-            ],
-            'validators' => [
-                NotEmpty::class     => [
-                    'name'    => NotEmpty::class,
-                    'options' => [
-                        'type' => NotEmpty::NULL,
-                    ],
-                ],
-                Callback::class     => [
-                    'name'    => Callback::class,
-                    'options' => [
-                        'callback' => AddressValidator::class
-                            . '::validate',
-                        'messages' => [
-                            Callback::INVALID_VALUE => 'error_empty_address_value',
-                        ],
-                    ],
-                ],
-                StringLength::class => [
-                    'name'    => StringLength::class,
-                    'options' => [
-                        'max' => 255
-                    ]
-                ],
-            ],
-        ],
-        'line2'   => [
-            'name'       => 'line2',
-            'required' => false,
-            'filters'    => [
-                StringTrim::class => [
-                    'name' => StringTrim::class,
-                ],
-            ],
-            'validators' => [
-                StringLength::class => [
-                    'name'    => StringLength::class,
-                    'options' => [
-                        'max' => 255
-                    ]
-                ],
-            ],
-        ],
-        'zip'     => [
-            'name'       => 'zip',
-            'filters'    => [
-                StringTrim::class => [
-                    'name' => StringTrim::class,
-                ],
-            ],
-            'validators' => [
-                NotEmpty::class     => [
-                    'name'    => NotEmpty::class,
-                    'options' => [
-                        'type' => NotEmpty::NULL,
-                    ],
-                ],
-                Callback::class     => [
-                    'name'    => Callback::class,
-                    'options' => [
-                        'callback' => AddressValidator::class
-                            . '::validate',
-                        'messages' => [
-                            Callback::INVALID_VALUE => 'error_empty_address_value',
-                        ],
-                    ],
-                ],
-                StringLength::class => [
-                    'name'    => StringLength::class,
-                    'options' => [
-                        'max' => 255
-                    ]
-                ],
-            ],
-        ],
-        'city'    => [
-            'name'       => 'city',
-            'filters'    => [
-                StringTrim::class => [
-                    'name' => StringTrim::class,
-                ],
-            ],
-            'validators' => [
-                NotEmpty::class     => [
-                    'name'    => NotEmpty::class,
-                    'options' => [
-                        'type' => NotEmpty::NULL,
-                    ],
-                ],
-                Callback::class     => [
-                    'name'    => Callback::class,
-                    'options' => [
-                        'callback' => AddressValidator::class
-                            . '::validate',
-                        'messages' => [
-                            Callback::INVALID_VALUE => 'error_empty_address_value',
-                        ],
-                    ],
-                ],
-                StringLength::class => [
-                    'name'    => StringLength::class,
-                    'options' => [
-                        'max' => 255
-                    ]
-                ],
-            ],
-        ],
-        'country' => [
-            'name'       => 'country',
-            'filters'    => [
-                StringTrim::class => [
-                    'name' => StringTrim::class,
-                ],
-            ],
-            'validators' => [
-                NotEmpty::class     => [
-                    'name'    => NotEmpty::class,
-                    'options' => [
-                        'type' => NotEmpty::NULL,
-                    ],
-                ],
-                Callback::class     => [
-                    'name'    => Callback::class,
-                    'options' => [
-                        'callback' => AddressValidator::class
-                            . '::validate',
-                        'messages' => [
-                            Callback::INVALID_VALUE => 'error_empty_address_value',
-                        ],
-                    ],
-                ],
-                StringLength::class => [
-                    'name'    => StringLength::class,
-                    'options' => [
-                        'max' => 255
-                    ]
-                ],
-            ],
-        ],
-    ],
-];
diff --git a/module/fid/config/admin-edit-form.php b/module/fid/config/admin-edit-form.php
new file mode 100644
index 0000000000000000000000000000000000000000..81322e19f9306857c29d156410b139a279e0a6c4
--- /dev/null
+++ b/module/fid/config/admin-edit-form.php
@@ -0,0 +1,262 @@
+<?php
+/**
+ * Copyright (C) 2019 Leipzig University Library
+ *
+ * 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.
+ *
+ * @author  Sebastian Kehr <kehr@ub.uni-leipzig.de>
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU GPLv2
+ */
+
+use fid\Hydrator\UserHydrator;
+use fid\InputFilter\AdminEditFormInputFilter;
+use fid\InputFilter\RootAwareBaseInputFilter;
+use Zend\Filter\StringTrim;
+use Zend\Form\Element\Collection;
+use Zend\Form\Element\Hidden;
+use Zend\Form\Element\Radio;
+use Zend\Form\Element\Select;
+use Zend\Form\Element\Submit;
+use Zend\Form\Element\Text;
+use Zend\Validator\Regex;
+use Zend\Validator\StringLength;
+
+return [
+    'name'     => 'admin-edit-form',
+    'hydrator' => UserHydrator::class,
+    'elements' => [
+        'id'             => [
+            'spec' => [
+                'name' => 'id',
+                'type' => Hidden::class,
+            ],
+        ],
+        'salutation'     => [
+            'spec' => [
+                'name'    => 'salutation',
+                'type'    => Select::class,
+                'options' => [
+                    'label'        => 'label_salutation',
+                    'options'      => [
+                        'mr'  => [
+                            'value' => 'mr',
+                            'label' => 'label_salutation_mr',
+                        ],
+                        'mrs' => [
+                            'value' => 'mrs',
+                            'label' => 'label_salutation_mrs',
+                        ]
+                    ],
+                    'empty_option' => '',
+                ],
+            ],
+        ],
+        'academic_title' => [
+            'spec' => [
+                'name'    => 'academic_title',
+                'type'    => Text::class,
+                'options' => [
+                    'label' => 'label_academic_title',
+                ],
+            ],
+        ],
+        'firstname'      => [
+            'spec' => [
+                'name'       => 'firstname',
+                'type'       => Text::class,
+                'options'    => [
+                    'label' => 'label_firstname',
+                ],
+                'attributes' => [
+                    'required' => true,
+                ],
+            ],
+        ],
+        'lastname'       => [
+            'spec' => [
+                'name'       => 'lastname',
+                'type'       => Text::class,
+                'options'    => [
+                    'label' => 'label_lastname',
+                ],
+                'attributes' => [
+                    'required' => true,
+                ],
+            ],
+        ],
+        'home_library'   => [
+            'spec' => [
+                'name'       => 'home_library',
+                'type'       => Select::class,
+                'options'    => [
+                    'label'              => 'label_home_library',
+                    'use_hidden_element' => true,
+                ],
+                'attributes' => [
+                    'required' => true,
+                ],
+            ],
+        ],
+        'college'        => [
+            'spec' => [
+                'name'    => 'college',
+                'type'    => Text::class,
+                'options' => [
+                    'label' => 'label_college',
+                ]
+            ],
+        ],
+        'job_title'      => [
+            'spec' => [
+                'name'       => 'job_title',
+                'type'       => Radio::class,
+                'options'    => [
+                    'label'         => 'label_job_title',
+                    'value_options' => [
+                        'job_title_0',
+                        'job_title_1'
+                    ],
+                ],
+                'attributes' => [
+                    'required' => true,
+                ],
+            ],
+        ],
+        'permissions'    => [
+            'spec' => [
+                'name'    => 'permissions',
+                'type'    => Collection::class,
+                'options' => [
+                    'label'          => 'label_permissions',
+                    'target_element' => [
+                        'name'    => 'permission',
+                        'type'    => Select::class,
+                        'options' => [
+                            'value_options' => [
+                                'denied'    => 'permission_status_denied',
+                                'requested' => 'permission_status_requested',
+                                'granted'   => 'permission_status_granted',
+                            ],
+                        ],
+                    ],
+                ],
+            ],
+        ],
+        'submit'         => [
+    'spec' => [
+        'name'       => 'submit',
+        'type'       => Submit::class,
+        'attributes' => [
+            'value' => 'label_update_submit',
+        ],
+    ],
+],
+    ],
+    'input_filter' => [
+    'type'           => RootAwareBaseInputFilter::class,
+    'id'             => [
+        'name'     => 'id',
+        'required' => true,
+    ],
+    'salutation'     => [
+        'name'     => 'salutation',
+        'required' => false,
+        'filters'  => [
+            StringTrim::class => [
+                'name' => StringTrim::class,
+            ],
+        ],
+    ],
+    'academic_title' => [
+        'name'     => 'academic_title',
+        'required' => false,
+        'filters'  => [
+            StringTrim::class => [
+                'name' => StringTrim::class,
+            ],
+        ],
+    ],
+    'firstname'      => [
+        'name'       => 'firstname',
+        'required'   => false,
+        'filters'    => [
+            StringTrim::class => [
+                'name' => StringTrim::class,
+            ],
+        ],
+        'validators' => [
+            StringLength::class => [
+                'name'    => StringLength::class,
+                'options' => [
+                    'max' => 255
+                ],
+            ],
+            Regex::class        => [
+                'name'    => Regex::class,
+                'options' => [
+                    'pattern' => '/^\D*$/',
+                ],
+            ],
+        ],
+    ],
+    'lastname'       => [
+        'name'       => 'lastname',
+        'required'   => false,
+        'filters'    => [
+            StringTrim::class => [
+                'name' => StringTrim::class,
+            ],
+        ],
+        'validators' => [
+            StringLength::class => [
+                'name'    => StringLength::class,
+                'options' => [
+                    'max' => 255
+                ]
+            ],
+            Regex::class        => [
+                'name'    => Regex::class,
+                'options' => [
+                    'pattern' => '/^\D*$/',
+                ],
+            ],
+        ],
+    ],
+    'home_library'   => [
+        'name'    => 'home_library',
+        'filters' => [
+            StringTrim::class => [
+                'name' => StringTrim::class,
+            ],
+        ],
+    ],
+    'college'        => [
+        'name'     => 'college',
+        'required' => false,
+        'filters'  => [
+            StringTrim::class => [
+                'name' => StringTrim::class,
+            ],
+        ],
+    ],
+    'job_title'      => [
+        'name'     => 'job_title',
+        'required' => true,
+    ],
+    'submit'         => [
+        'name'     => 'submit',
+        'required' => true,
+    ],
+],
+];
\ No newline at end of file
diff --git a/module/fid/config/module.config.php b/module/fid/config/module.config.php
index 77b6b0c368be6037f68d6265dde8c9d80300d0ce..a1ae1d9475eaf3a0834cdeaa2fade6e00f5c6cd5 100644
--- a/module/fid/config/module.config.php
+++ b/module/fid/config/module.config.php
@@ -21,14 +21,15 @@
 
 use fid\Controller\UserController;
 use fid\Controller\UserControllerFactory;
-use fid\FormModel\UsernameChangeModel;
+use fid\Filter\PermissionsFilter;
+use fid\Filter\PermissionsFilterFactory;
 use fid\FormModel\PasswordChangeModel;
 use fid\FormModel\PasswordResetModel;
-use fid\FormModel\UserCreateModel;
-use fid\FormModel\UserInitModel;
-use fid\FormModel\UserUpdateModel;
+use fid\FormModel\UsernameChangeModel;
 use fid\Helper\FormLabel;
 use fid\Helper\TranslatorDelegator;
+use fid\Hydrator\UserHydrator;
+use fid\Hydrator\UserHydratorDelegatorFactory;
 use fid\Listener\ErrorListener;
 use fid\Listener\ErrorListenerFactory;
 use fid\Listener\LocaleListener;
@@ -54,12 +55,28 @@ use Zend\ServiceManager\Factory\InvokableFactory;
 
 return [
     'forms'              => [
-        UserInitModel::class       => require_once 'user-init-form.php',
-        UserCreateModel::class     => require_once 'user-create-form.php',
-        UserUpdateModel::class     => require_once 'user-update-form.php',
-        PasswordResetModel::class  => require_once 'password-reset-form.php',
-        PasswordChangeModel::class => require_once 'password-change-form.php',
-        UsernameChangeModel::class => require_once 'username-change-form.php',
+        'user-init-form'           => require 'user-init-form.php',
+        'user-create-form'         => require 'user-create-form.php',
+        'user-update-form'         => require 'user-update-form.php',
+        'admin-edit-form'          => require 'admin-edit-form.php',
+        PasswordResetModel::class  => require 'password-reset-form.php',
+        PasswordChangeModel::class => require 'password-change-form.php',
+        UsernameChangeModel::class => require 'username-change-form.php',
+    ],
+    'filters'            => [
+        'factories' => [
+            PermissionsFilter::class => PermissionsFilterFactory::class,
+        ]
+    ],
+    'hydrators'          => [
+        'factories'  => [
+            UserHydrator::class => InvokableFactory::class,
+        ],
+        'delegators' => [
+            UserHydrator::class => [
+                UserHydratorDelegatorFactory::class,
+            ],
+        ],
     ],
     'controllers'        => [
         'factories' => [
@@ -70,7 +87,7 @@ return [
         ErrorListener::class,
         LocaleListener::class,
     ],
-    // TODO: add alias to vufind core
+    // TODO: issue PR to add alias to vufind core
     'controller_plugins' => [
         'aliases' => [
             'flashmessenger' => FlashMessenger::class,
@@ -96,8 +113,8 @@ return [
             LocaleListener::class   => InvokableFactory::class,
         ],
     ],
-    'view_helpers' => [
-        'aliases' => [
+    'view_helpers'       => [
+        'aliases'   => [
             'formLabel' => FormLabel::class,
         ],
         'factories' => [
@@ -106,7 +123,7 @@ return [
     ],
     'vufind'             => [
         'plugin_managers' => [
-            'auth'       => [
+            'auth'            => [
                 'aliases'   => [
                     'fid' => Authenticator::class,
                 ],
@@ -114,7 +131,7 @@ return [
                     Authenticator::class => AuthenticatorFactory::class,
                 ],
             ],
-            'db_row'     => [
+            'db_row'          => [
                 'aliases'    => [
                     BaseUser::class => User::class,
                 ],
@@ -127,7 +144,7 @@ return [
                     User::class => UserFactory::class,
                 ],
             ],
-            'ils_driver' => [
+            'ils_driver'      => [
                 'aliases'   => [
                     'fid' => Fid::class,
                 ],
@@ -135,13 +152,13 @@ return [
                     Fid::class => FidFactory::class,
                 ],
             ],
-            'recordtab' => [
+            'recordtab'       => [
                 'invokables' => [
                     'worldcat' => 'fid\RecordTab\Worldcat',
                 ],
             ],
             'resolver_driver' => [
-                'factories' => [
+                'factories'  => [
                     Ezb::class =>
                         DriverWithHttpClientFactory::class,
                 ],
@@ -150,20 +167,20 @@ return [
                         EzbDelegatorFactory::class,
                     ],
                 ],
-                'aliases' => [
+                'aliases'    => [
                     'VuFind\Resolver\Driver\Ezb' => Ezb::class,
                 ],
             ],
         ],
     ],
     // Authorization configuration:
-    'zfc_rbac' => [
+    'zfc_rbac'           => [
         'vufind_permission_provider_manager' => [
             'factories' => [
                 'fid\Role\PermissionProvider\FidApiPermission' =>
                     'fid\Role\PermissionProvider\Factory::getFidApiPermission'
             ],
-            'aliases' => [
+            'aliases'   => [
                 'FidApiPermission' => 'fid\Role\PermissionProvider\FidApiPermission'
             ]
         ]
@@ -177,7 +194,7 @@ return [
                     'route' => '/fid',
                 ],
                 'child_routes'  => [
-                    'user' => [
+                    'user'  => [
                         'may_terminate' => false,
                         'type'          => 'literal',
                         'options'       => [
@@ -277,14 +294,14 @@ return [
                             ]
                         ],
                     ],
-                    'admin'          => [
+                    'admin' => [
                         'may_terminate' => false,
                         'type'          => 'literal',
                         'options'       => [
                             'route' => '/admin'
                         ],
                         'child_routes'  => [
-                            'list'          => [
+                            'list' => [
                                 'type'    => 'literal',
                                 'options' => [
                                     'route'    => '/list',
@@ -294,7 +311,7 @@ return [
                                     ],
                                 ],
                             ],
-                            'edit'          => [
+                            'edit' => [
                                 'type'    => 'Zend\Router\Http\Segment',
                                 'options' => [
                                     'route'    => '/edit/[:userid]',
diff --git a/module/fid/config/user-create-form.php b/module/fid/config/user-create-form.php
index 0e398fe9c80578edf43232c4f99532aec508c2fd..3d4969eae965f83a3a66fd148890e89cb4587887 100644
--- a/module/fid/config/user-create-form.php
+++ b/module/fid/config/user-create-form.php
@@ -19,20 +19,17 @@
  * @license http://opensource.org/licenses/gpl-2.0.php GNU GPLv2
  */
 
-use fid\FormModel\AddressValidator;
+use fid\Hydrator\UserHydrator;
+use fid\InputFilter\RootAwareBaseInputFilter;
 use Zend\Filter\Boolean;
 use Zend\Filter\StringTrim;
-use Zend\Filter\ToInt;
-use Zend\Filter\ToNull;
 use Zend\Form\Element\Checkbox;
-use Zend\Form\Element\Number;
 use Zend\Form\Element\Password;
 use Zend\Form\Element\Radio;
 use Zend\Form\Element\Select;
 use Zend\Form\Element\Submit;
 use Zend\Form\Element\Text;
-use Zend\Hydrator\ClassMethods;
-use Zend\Validator\Callback;
+use Zend\Form\InputFilterProviderFieldset;
 use Zend\Validator\EmailAddress;
 use Zend\Validator\Identical;
 use Zend\Validator\NotEmpty;
@@ -40,9 +37,10 @@ use Zend\Validator\Regex;
 use Zend\Validator\StringLength;
 
 return [
-    'hydrator'     => ClassMethods::class,
+    'name'         => 'user-create-form',
+    'hydrator'     => UserHydrator::class,
     'elements'     => [
-        'username'             => [
+        'username'              => [
             'spec' => [
                 'name'       => 'username',
                 'type'       => Text::class,
@@ -50,11 +48,11 @@ return [
                     'label' => 'label_username',
                 ],
                 'attributes' => [
-                    'required' => 'required',
+                    'required' => true,
                 ],
             ],
         ],
-        'password'             => [
+        'password'              => [
             'spec' => [
                 'name'       => 'password',
                 'type'       => Password::class,
@@ -62,23 +60,23 @@ return [
                     'label' => 'label_password',
                 ],
                 'attributes' => [
-                    'required' => 'required',
+                    'required' => true,
                 ],
             ],
         ],
-        'passwordConfirmation' => [
+        'password_confirmation' => [
             'spec' => [
-                'name'       => 'passwordConfirmation',
+                'name'       => 'password_confirmation',
                 'type'       => Password::class,
                 'options'    => [
                     'label' => 'label_password_confirmation',
                 ],
                 'attributes' => [
-                    'required' => 'required',
+                    'required' => true,
                 ],
             ],
         ],
-        'salutation'           => [
+        'salutation'            => [
             'spec' => [
                 'name'    => 'salutation',
                 'type'    => Select::class,
@@ -92,22 +90,22 @@ return [
                         'mrs' => [
                             'value' => 'mrs',
                             'label' => 'label_salutation_mrs',
-                        ]
+                        ],
                     ],
                     'empty_option' => '',
                 ],
             ],
         ],
-        'academicTitle'        => [
+        'academic_title'        => [
             'spec' => [
-                'name'    => 'academicTitle',
+                'name'    => 'academic_title',
                 'type'    => Text::class,
                 'options' => [
                     'label' => 'label_academic_title',
                 ],
             ],
         ],
-        'firstname'            => [
+        'firstname'             => [
             'spec' => [
                 'name'       => 'firstname',
                 'type'       => Text::class,
@@ -115,11 +113,11 @@ return [
                     'label' => 'label_firstname',
                 ],
                 'attributes' => [
-                    'required' => 'required',
+                    'required' => true,
                 ],
             ],
         ],
-        'lastname'             => [
+        'lastname'              => [
             'spec' => [
                 'name'       => 'lastname',
                 'type'       => Text::class,
@@ -127,121 +125,65 @@ return [
                     'label' => 'label_lastname',
                 ],
                 'attributes' => [
-                    'required' => 'required',
+                    'required' => true,
                 ],
             ],
         ],
-        'homeLibrary'          => [
+        'home_library'          => [
             'spec' => [
-                'name'       => 'homeLibrary',
+                'name'       => 'home_library',
                 'type'       => Select::class,
                 'options'    => [
                     'label'        => 'label_home_library',
                     'empty_option' => '',
                 ],
                 'attributes' => [
-                    'required' => 'required',
+                    'required' => true,
                 ],
             ],
         ],
-        'accessLevel'          => [
+        'job_title'             => [
             'spec' => [
-                'name'       => 'accessLevel',
+                'name'       => 'job_title',
                 'type'       => Radio::class,
                 'options'    => [
-                    'label' => 'label_access_level',
+                    'label'         => 'label_job_title',
+                    'value_options' => [
+                        'job_title_0',
+                        'job_title_1'
+                    ],
                 ],
                 'attributes' => [
-                    'required' => 'required',
+                    'required' => true,
                 ],
             ],
         ],
-        'yearOfBirth'          => [
-            'spec' => [
-                'name'       => 'yearOfBirth',
-                'type'       => Number::class,
-                'options'    => [
-                    'label' => 'label_year_of_birth',
-                ],
-                'attributes' => [
-                    'min' => 1900,
-                    'max' => 2018,
-                ],
-            ]
-        ],
-        'jobTitle'             => [
-            'spec' => [
-                'name'    => 'jobTitle',
-                'type'    => Text::class,
-                'options' => [
-                    'label' => 'label_job_title',
-                ],
-            ],
-        ],
-        'college'              => [
+        'college'               => [
             'spec' => [
                 'name'    => 'college',
                 'type'    => Text::class,
                 'options' => [
                     'label' => 'label_college',
-                ]
-            ],
-        ],
-        'addressLine1'         => [
-            'spec' => [
-                'name'    => 'addressLine1',
-                'type'    => Text::class,
-                'options' => [
-                    'label' => 'label_address_line_1',
-                ]
-            ],
-        ],
-        'addressLine2'         => [
-            'spec' => [
-                'name'    => 'addressLine2',
-                'type'    => Text::class,
-                'options' => [
-                    'label' => 'label_address_line_2',
-                ]
-            ],
-        ],
-        'addressZip'         => [
-            'spec' => [
-                'name'    => 'addressZip',
-                'type'    => Text::class,
-                'options' => [
-                    'label' => 'label_address_zip',
-                ]
-            ],
-        ],
-        'addressCity'         => [
-            'spec' => [
-                'name'    => 'addressCity',
-                'type'    => Text::class,
-                'options' => [
-                    'label' => 'label_address_city',
-                ]
+                ],
             ],
         ],
-        'addressCountry'         => [
+        'addresses'             => require 'address-collection.php',
+        'data'                  => [
             'spec' => [
-                'name'    => 'addressCountry',
-                'type'    => Text::class,
-                'options' => [
-                    'label' => 'label_address_country',
-                ]
+                'name' => 'data',
+                'type' => InputFilterProviderFieldset::class,
             ],
         ],
-        'eulaAccepted'         => [
+        'eula_accepted'         => [
             'spec' => [
-                'name'       => 'eulaAccepted',
+                'name'       => 'eula_accepted',
                 'type'       => Checkbox::class,
                 'attributes' => [
-                    'required' => 'required',
+                    'required' => true,
                 ],
             ],
         ],
-        'submit'               => [
+        'submit'                => [
             'spec' => [
                 'name'       => 'submit',
                 'type'       => Submit::class,
@@ -252,9 +194,9 @@ return [
         ],
     ],
     'input_filter' => [
-        'username'             => [
+        'type'                  => RootAwareBaseInputFilter::class,
+        'username'              => [
             'name'       => 'username',
-            'required'   => true,
             'filters'    => [
                 StringTrim::class => [
                     'name' => StringTrim::class,
@@ -272,9 +214,8 @@ return [
                 ],
             ],
         ],
-        'password'             => [
+        'password'              => [
             'name'       => 'password',
-            'required'   => true,
             'filters'    => [
                 StringTrim::class => [
                     'name' => StringTrim::class,
@@ -301,11 +242,19 @@ return [
                         ],
                     ],
                 ],
-                Identical::class    => [
+            ],
+        ],
+        'password_confirmation' => [
+            'name'       => 'password_confirmation',
+            'validators' => [
+                NotEmpty::class  => [
+                    'name' => NotEmpty::class,
+                ],
+                Identical::class => [
                     'name'    => Identical::class,
                     'options' => [
                         'strict'   => false,
-                        'token'    => 'passwordConfirmation',
+                        'token'    => 'password',
                         'messages' => [
                             Identical::NOT_SAME => 'error_password_confirmation',
                         ],
@@ -313,16 +262,7 @@ return [
                 ],
             ],
         ],
-        'passwordConfirmation' => [
-            'name'       => 'passwordConfirmation',
-            'required'   => true,
-            'validators' => [
-                NotEmpty::class => [
-                    'name' => NotEmpty::class,
-                ],
-            ],
-        ],
-        'salutation'           => [
+        'salutation'            => [
             'name'     => 'salutation',
             'required' => false,
             'filters'  => [
@@ -331,10 +271,10 @@ return [
                 ],
             ],
         ],
-        'academicTitle'        => [
-            'name'     => 'academicTitle',
-            'required' => false,
-            'filters'  => [
+        'academic_title'        => [
+            'name'       => 'academic_title',
+            'required'   => false,
+            'filters'    => [
                 StringTrim::class => [
                     'name' => StringTrim::class,
                 ],
@@ -344,11 +284,11 @@ return [
                     'name'    => StringLength::class,
                     'options' => [
                         'max' => 255
-                    ]
+                    ],
                 ],
             ],
         ],
-        'firstname'            => [
+        'firstname'             => [
             'name'       => 'firstname',
             'required'   => true,
             'filters'    => [
@@ -371,7 +311,7 @@ return [
                 ],
             ],
         ],
-        'lastname'             => [
+        'lastname'              => [
             'name'       => 'lastname',
             'required'   => true,
             'filters'    => [
@@ -384,7 +324,7 @@ return [
                     'name'    => StringLength::class,
                     'options' => [
                         'max' => 255
-                    ]
+                    ],
                 ],
                 Regex::class        => [
                     'name'    => Regex::class,
@@ -394,128 +334,29 @@ return [
                 ],
             ],
         ],
-        'homeLibrary'          => [
-            'name'     => 'homeLibrary',
-            'required' => true,
-            'filters'  => [
-                StringTrim::class => [
-                    'name' => StringTrim::class,
-                ],
-            ],
-            'validators' => [
-                StringLength::class => [
-                    'name'    => StringLength::class,
-                    'options' => [
-                        'max' => 255
-                    ]
-                ],
-            ],
-        ],
-        'accessLevel'          => [
-            'name'     => 'accessLevel',
-            'required' => true,
-            'filters'  => [
-                StringTrim::class => [
-                    'name' => StringTrim::class,
-                ],
-            ],
-        ],
-        'yearOfBirth'          => [
-            'name'     => 'yearOfBirth',
-            'required' => false,
-            'filters'  => [
-                ToNull::class => [
-                    'name' => ToNull::class,
-                ],
-                ToInt::class  => [
-                    'name' => ToInt::class,
-                ],
-            ],
-        ],
-        'jobTitle'             => [
-            'name'     => 'jobTitle',
-            'required' => false,
-            'filters'  => [
-                StringTrim::class => [
-                    'name' => StringTrim::class,
-                ],
-            ],
-            'validators' => [
-                StringLength::class => [
-                    'name'    => StringLength::class,
-                    'options' => [
-                        'max' => 255
-                    ]
-                ],
-            ],
-        ],
-        'college'              => [
-            'name'     => 'college',
-            'required' => false,
-            'filters'  => [
-                StringTrim::class => [
-                    'name' => StringTrim::class,
-                ],
-            ],
-            'validators' => [
-                StringLength::class => [
-                    'name'    => StringLength::class,
-                    'options' => [
-                        'max' => 255
-                    ]
-                ],
-            ],
-        ],
-        'addressLine1'         => [
-            'name'       => 'addressLine1',
+        'home_library'          => [
+            'name'       => 'home_library',
+            'required'   => true,
             'filters'    => [
                 StringTrim::class => [
                     'name' => StringTrim::class,
                 ],
             ],
             'validators' => [
-                NotEmpty::class => [
-                    'name'    => NotEmpty::class,
-                    'options' => [
-                        'type' => NotEmpty::NULL,
-                    ],
-                ],
-                Callback::class => [
-                    'name'    => Callback::class,
-                    'options' => [
-                        'callback' => AddressValidator::class.'::init',
-                        'messages' => [
-                            Callback::INVALID_VALUE => 'error_empty_address_value',
-                        ],
-                    ],
-                ],
                 StringLength::class => [
                     'name'    => StringLength::class,
                     'options' => [
                         'max' => 255
-                    ]
+                    ],
                 ],
             ],
         ],
-        'addressLine2' => [
-            'name'       => 'addressLine2',
-            'required'   => false,
-            'filters'    => [
-                StringTrim::class => [
-                    'name' => StringTrim::class,
-                ],
-            ],
-            'validators' => [
-                StringLength::class => [
-                    'name'    => StringLength::class,
-                    'options' => [
-                        'max' => 255
-                    ]
-                ],
-            ],
+        'job_title'             => [
+            'name'     => 'job_title',
+            'required' => true,
         ],
-        'addressZip' => [
-            'name'       => 'addressZip',
+        'college'               => [
+            'name'       => 'college',
             'required'   => false,
             'filters'    => [
                 StringTrim::class => [
@@ -523,93 +364,16 @@ return [
                 ],
             ],
             'validators' => [
-                NotEmpty::class => [
-                    'name'    => NotEmpty::class,
-                    'options' => [
-                        'type' => NotEmpty::NULL,
-                    ],
-                ],
-                Callback::class => [
-                    'name'    => Callback::class,
-                    'options' => [
-                        'callback' => AddressValidator::class.'::init',
-                        'messages' => [
-                            Callback::INVALID_VALUE => 'error_empty_address_value',
-                        ],
-                    ],
-                ],
-                StringLength::class => [
-                    'name'    => StringLength::class,
-                    'options' => [
-                        'max' => 255
-                    ]
-                ],
-            ],
-        ],
-        'addressCity' => [
-            'name'       => 'addressCity',
-            'filters'    => [
-                StringTrim::class => [
-                    'name' => StringTrim::class,
-                ],
-            ],
-            'validators' => [
-                NotEmpty::class => [
-                    'name'    => NotEmpty::class,
-                    'options' => [
-                        'type' => NotEmpty::NULL,
-                    ],
-                ],
-                Callback::class => [
-                    'name'    => Callback::class,
-                    'options' => [
-                        'callback' => AddressValidator::class.'::init',
-                        'messages' => [
-                            Callback::INVALID_VALUE => 'error_empty_address_value',
-                        ],
-                    ],
-                ],
                 StringLength::class => [
                     'name'    => StringLength::class,
                     'options' => [
                         'max' => 255
-                    ]
-                ],
-            ],
-        ],
-        'addressCountry' => [
-            'name'       => 'addressCountry',
-            'filters'    => [
-                StringTrim::class => [
-                    'name' => StringTrim::class,
-                ],
-            ],
-            'validators' => [
-                NotEmpty::class => [
-                    'name'    => NotEmpty::class,
-                    'options' => [
-                        'type' => NotEmpty::NULL,
-                    ],
-                ],
-                Callback::class => [
-                    'name'    => Callback::class,
-                    'options' => [
-                        'callback' => AddressValidator::class.'::init',
-                        'messages' => [
-                            Callback::INVALID_VALUE => 'error_empty_address_value',
-                        ],
                     ],
                 ],
-                StringLength::class => [
-                    'name'    => StringLength::class,
-                    'options' => [
-                        'max' => 255
-                    ]
-                ],
             ],
         ],
-        'eulaAccepted'         => [
-            'name'       => 'eulaAccepted',
+        'eula_accepted'         => [
+            'name'       => 'eula_accepted',
             'required'   => true,
             'filters'    => [
                 Boolean::class => [
@@ -627,7 +391,7 @@ return [
                 ],
             ],
         ],
-        'submit'               => [
+        'submit'                => [
             'name'     => 'submit',
             'required' => true,
         ],
diff --git a/module/fid/config/user-init-form.php b/module/fid/config/user-init-form.php
index 24a7a49a809cc36169ac9363aa6ce2763a62cc62..0718f0fa86d70aa22a2a36ef93f88a05be361d7c 100644
--- a/module/fid/config/user-init-form.php
+++ b/module/fid/config/user-init-form.php
@@ -19,13 +19,13 @@
  * @license http://opensource.org/licenses/gpl-2.0.php GNU GPLv2
  */
 
+use fid\Hydrator\UserHydrator;
 use Zend\Filter\Boolean;
 use Zend\Filter\StringTrim;
 use Zend\Form\Element\Checkbox;
 use Zend\Form\Element\Email;
 use Zend\Form\Element\Submit;
 use Zend\Form\Element\Text;
-use Zend\Hydrator\ClassMethods;
 use Zend\Validator\EmailAddress;
 use Zend\Validator\Identical;
 use Zend\Validator\NotEmpty;
@@ -33,7 +33,8 @@ use Zend\Validator\Regex;
 use Zend\Validator\StringLength;
 
 return [
-    'hydrator'     => ClassMethods::class,
+    'name'         => 'user-init-form',
+    'hydrator'     => UserHydrator::class,
     'elements'     => [
         'username'             => [
             'spec' => [
@@ -43,19 +44,19 @@ return [
                     'label' => 'label_username',
                 ],
                 'attributes' => [
-                    'required' => 'required',
+                    'required' => true,
                 ],
             ],
         ],
-        'usernameConfirmation' => [
+        'username_confirmation' => [
             'spec' => [
-                'name'       => 'usernameConfirmation',
+                'name'       => 'username_confirmation',
                 'type'       => Text::class,
                 'options'    => [
                     'label' => 'label_username_confirmation',
                 ],
                 'attributes' => [
-                    'required' => 'required',
+                    'required' => true,
                 ],
             ],
         ],
@@ -67,7 +68,7 @@ return [
                     'label' => 'label_firstname',
                 ],
                 'attributes' => [
-                    'required' => 'required',
+                    'required' => true,
                 ],
             ],
         ],
@@ -79,16 +80,16 @@ return [
                     'label' => 'label_lastname',
                 ],
                 'attributes' => [
-                    'required' => 'required',
+                    'required' => true,
                 ],
             ],
         ],
-        'eulaAccepted'         => [
+        'eula_accepted'         => [
             'spec' => [
-                'name'       => 'eulaAccepted',
+                'name'       => 'eula_accepted',
                 'type'       => Checkbox::class,
                 'attributes' => [
-                    'required' => 'required',
+                    'required' => true,
                 ],
             ],
         ],
@@ -123,8 +124,8 @@ return [
                 ],
             ],
         ],
-        'usernameConfirmation' => [
-            'name'       => 'usernameConfirmation',
+        'username_confirmation' => [
+            'name'       => 'username_confirmation',
             'required'   => true,
             'validators' => [
                 Identical::class => [
@@ -185,8 +186,8 @@ return [
                 ],
             ],
         ],
-        'eulaAccepted'         => [
-            'name'       => 'eulaAccepted',
+        'eula_accepted'         => [
+            'name'       => 'eula_accepted',
             'required'   => true,
             'filters'    => [
                 Boolean::class => [
@@ -205,8 +206,8 @@ return [
             ],
         ],
         'submit'               => [
-            'name'       => 'submit',
-            'required'   => true,
+            'name'     => 'submit',
+            'required' => true,
         ],
     ],
 ];
\ No newline at end of file
diff --git a/module/fid/config/user-update-form.php b/module/fid/config/user-update-form.php
index b7c70903baa2a2cbb51401bff7cb9379ca02b866..067e4686eb64d314d61c8eee0e8fd5a546053b16 100644
--- a/module/fid/config/user-update-form.php
+++ b/module/fid/config/user-update-form.php
@@ -19,33 +19,28 @@
  * @license http://opensource.org/licenses/gpl-2.0.php GNU GPLv2
  */
 
-use Zend\Filter\Callback;
+use fid\Hydrator\UserHydrator;
+use fid\InputFilter\RootAwareBaseInputFilter;
 use Zend\Filter\StringTrim;
-use Zend\Filter\ToInt;
-use Zend\Filter\ToNull;
-use Zend\Form\Element\Collection;
 use Zend\Form\Element\Hidden;
-use Zend\Form\Element\MultiCheckbox;
-use Zend\Form\Element\Number;
 use Zend\Form\Element\Select;
 use Zend\Form\Element\Submit;
 use Zend\Form\Element\Text;
-use Zend\Hydrator\ClassMethods;
-use Zend\Validator\Explode;
-use Zend\Validator\InArray;
+use Zend\Form\InputFilterProviderFieldset;
 use Zend\Validator\Regex;
 use Zend\Validator\StringLength;
 
 return [
-    'hydrator'     => ClassMethods::class,
+    'name'         => 'user-update-form',
+    'hydrator'     => UserHydrator::class,
     'elements'     => [
-        'userId'   => [
+        'id'             => [
             'spec' => [
-                'name'       => 'userId',
-                'type'       => Hidden::class,
+                'name' => 'id',
+                'type' => Hidden::class,
             ],
         ],
-        'salutation'    => [
+        'salutation'     => [
             'spec' => [
                 'name'    => 'salutation',
                 'type'    => Select::class,
@@ -65,66 +60,52 @@ return [
                 ],
             ],
         ],
-        'academicTitle' => [
+        'academic_title' => [
             'spec' => [
-                'name'    => 'academicTitle',
+                'name'    => 'academic_title',
                 'type'    => Text::class,
                 'options' => [
                     'label' => 'label_academic_title',
                 ],
             ],
         ],
-        'firstname'     => [
+        'firstname'      => [
             'spec' => [
                 'name'       => 'firstname',
                 'type'       => Text::class,
                 'options'    => [
                     'label' => 'label_firstname',
                 ],
+                'attributes' => [
+                    'required' => true,
+                ],
             ],
         ],
-        'lastname'      => [
+        'lastname'       => [
             'spec' => [
                 'name'       => 'lastname',
                 'type'       => Text::class,
                 'options'    => [
                     'label' => 'label_lastname',
                 ],
-            ],
-        ],
-        'homeLibrary'   => [
-            'spec' => [
-                'name'       => 'homeLibrary',
-                'type'       => Select::class,
-                'options'    => [
-                    'label'        => 'label_home_library',
-                    'empty_option' => '',
+                'attributes' => [
+                    'required' => true,
                 ],
             ],
         ],
-        'yearOfBirth'   => [
+        'home_library'   => [
             'spec' => [
-                'name'       => 'yearOfBirth',
-                'type'       => Number::class,
+                'name'       => 'home_library',
+                'type'       => Select::class,
                 'options'    => [
-                    'label' => 'label_year_of_birth',
+                    'label' => 'label_home_library',
                 ],
                 'attributes' => [
-                    'min' => 1900,
-                    'max' => 2018,
-                ],
-            ]
-        ],
-        'jobTitle'      => [
-            'spec' => [
-                'name'    => 'jobTitle',
-                'type'    => Text::class,
-                'options' => [
-                    'label' => 'label_job_title',
+                    'required' => true,
                 ],
             ],
         ],
-        'college'       => [
+        'college'        => [
             'spec' => [
                 'name'    => 'college',
                 'type'    => Text::class,
@@ -133,33 +114,30 @@ return [
                 ]
             ],
         ],
-        'permissions'   => [
+        'addresses'      => require 'address-collection.php',
+        'data'           => [
             'spec' => [
-                'name'       => 'permissions',
-                'type'       => MultiCheckbox::class,
-                'options'    => [
-                    'label'        => 'label_permissions',
-                    'checked_value' => 'granted',
-                    'unchecked_value' => 'denied',
-                ],
+                'name' => 'data',
+                'type' => InputFilterProviderFieldset::class,
             ],
         ],
-        'submit'        => [
+        'submit'         => [
             'spec' => [
                 'name'       => 'submit',
                 'type'       => Submit::class,
                 'attributes' => [
-                    'value' => 'label_submit',
+                    'value' => 'label_update_submit',
                 ],
             ],
         ],
     ],
-    'fieldsets' => [
-        'addresses'     => require_once 'address-collection.php',
-    ],
     'input_filter' => [
-        'addresses' => require_once 'address-input-filter.php',
-        'salutation'    => [
+        'type'           => RootAwareBaseInputFilter::class,
+        'id'             => [
+            'name'     => 'id',
+            'required' => true,
+        ],
+        'salutation'     => [
             'name'     => 'salutation',
             'required' => false,
             'filters'  => [
@@ -168,8 +146,8 @@ return [
                 ],
             ],
         ],
-        'academicTitle' => [
-            'name'     => 'academicTitle',
+        'academic_title' => [
+            'name'     => 'academic_title',
             'required' => false,
             'filters'  => [
                 StringTrim::class => [
@@ -177,7 +155,7 @@ return [
                 ],
             ],
         ],
-        'firstname'     => [
+        'firstname'      => [
             'name'       => 'firstname',
             'required'   => false,
             'filters'    => [
@@ -200,7 +178,7 @@ return [
                 ],
             ],
         ],
-        'lastname'      => [
+        'lastname'       => [
             'name'       => 'lastname',
             'required'   => false,
             'filters'    => [
@@ -223,37 +201,16 @@ return [
                 ],
             ],
         ],
-        'homeLibrary'   => [
-            'name'       => 'homeLibrary',
-            'required'   => false,
-            'filters'    => [
-                StringTrim::class => [
-                    'name' => StringTrim::class,
-                ],
-            ],
-        ],
-        'yearOfBirth'   => [
-            'name'     => 'yearOfBirth',
-            'required' => false,
-            'filters'  => [
-                ToNull::class => [
-                    'name' => ToNull::class,
-                ],
-                ToInt::class  => [
-                    'name' => ToInt::class,
-                ],
-            ],
-        ],
-        'jobTitle'      => [
-            'name'     => 'jobTitle',
-            'required' => false,
+        'home_library'   => [
+            'name'     => 'home_library',
+            'required' => true,
             'filters'  => [
                 StringTrim::class => [
                     'name' => StringTrim::class,
                 ],
             ],
         ],
-        'college'       => [
+        'college'        => [
             'name'     => 'college',
             'required' => false,
             'filters'  => [
@@ -262,38 +219,9 @@ return [
                 ],
             ],
         ],
-        'permissions'   => [
-            'name'      => 'permissions',
-            'required'  => false,
-            'validators' => [
-                Explode::class => [
-                    'name' => Explode::class,
-                    'options' => [
-                        'validator' => [
-                            'name'    => InArray::class,
-                            'options' => [
-                                'haystack' => [
-                                    'granted',
-                                    'denied',
-                                    'requested'
-                                ],
-                            ]
-                        ],
-                    ],
-                ],
-            ],
-            'filters'  => [
-                Callback::class => [
-                    'name' => Callback::class,
-                    'options' => [
-                        'callback' => '\fid\Controller\UserController::combinePermissionsArray'
-                    ]
-                ],
-            ],
-        ],
-        'submit'               => [
-            'name'       => 'submit',
-            'required'   => true,
+        'submit'         => [
+            'name'     => 'submit',
+            'required' => true,
         ],
     ],
-];
+];
\ No newline at end of file
diff --git a/module/fid/src/Controller/UserController.php b/module/fid/src/Controller/UserController.php
index b6b0678ccc471651441995b17e3dbf9b8240ef51..976ae2f35823e6a0294317bbac03a1db29425092 100644
--- a/module/fid/src/Controller/UserController.php
+++ b/module/fid/src/Controller/UserController.php
@@ -24,21 +24,16 @@ namespace fid\Controller;
 
 use fid\FormModel\PasswordChangeModel;
 use fid\FormModel\PasswordResetModel;
-use fid\FormModel\UserCreateModel;
-use fid\FormModel\UserInitModel;
-use fid\FormModel\UserUpdateModel;
 use fid\FormModel\UsernameChangeModel;
 use fid\Service\Client;
 use fid\Service\ClientException;
-use fid\Service\DataTransferObject\Address;
 use fid\Service\DataTransferObject\Library;
 use fid\Service\DataTransferObject\User;
 use fid\Service\UserNotAuthorizedException;
-use Symfony\Component\Serializer\SerializerAwareTrait;
 use VuFind\Auth\Manager as AuthManager;
 use VuFind\Controller\AbstractBase;
 use VuFind\Exception\Auth as AuthException;
-use Zend\Form\Element\MultiCheckbox;
+use Zend\Form\Element\Checkbox;
 use Zend\Form\Element\Radio;
 use Zend\Form\Element\Select;
 use Zend\Form\Form;
@@ -50,8 +45,6 @@ use Zend\View\Model\ViewModel;
 
 class UserController extends AbstractBase
 {
-    use SerializerAwareTrait;
-
     /**
      * @var AuthManager
      */
@@ -93,9 +86,10 @@ class UserController extends AbstractBase
      */
     public function initAction()
     {
+        /** @var Form $form */
         /** @var Request $request */
         $request = $this->getRequest();
-        $form = $this->serviceLocator->get(UserInitModel::class);
+        $form = $this->serviceLocator->get('user-init-form');
         $forwarded = $this->params()->fromRoute('forwarded', false);
 
         if ($submitted = $this->formWasSubmitted()) {
@@ -105,6 +99,10 @@ class UserController extends AbstractBase
             }
         }
 
+        $action = $this->url()->fromRoute('fid/user/init');
+        $form->setAttribute('action', $action);
+        $form->prepare();
+
         $view = $this->createViewModel();
         $view->setVariables(compact('form'));
         $view->setTemplate('fid/user/init');
@@ -112,13 +110,60 @@ class UserController extends AbstractBase
         return $view;
     }
 
+    /**
+     * @param Form $form
+     *
+     * @return mixed|Response
+     */
+    protected function init(Form $form)
+    {
+        /** @var User $user */
+        $messenger = $this->getMessenger();
+        $user = $form->getHydrator()->hydrate($form->getData(), new User());
+
+        /** @noinspection PhpUndefinedFieldInspection */
+        $query['lng'] = $this->layout()->userLang;
+        $username = $query['username'] = $user->getUsername();
+        $firstname = $query['firstname'] = $user->getFirstname();
+        $lastname = $query['lastname'] = $user->getLastname();
+        $baseUrl = $this->url()->fromRoute('fid/user/create',
+            [], ['query' => $query, 'force_canonical' => true]);
+
+        try {
+            $this->client->requestRegistrationLink($baseUrl, $username,
+                $firstname, $lastname);
+        } catch (ClientException $exception) {
+            $message = $exception->getCode() === 400
+                ? 'fid::user_init_error_username'
+                : 'fid::user_init_error';
+            $messenger->addErrorMessage($this->translate($message));
+            return $this->forward()->dispatch(self::class, [
+                'action'    => 'init',
+                'forwarded' => true
+            ]);
+        }
+
+        $message = $this->translate('fid::user_init_success');
+        $messenger->addSuccessMessage(sprintf($message, $username));
+        return $this->redirect()->toRoute('myresearch-home');
+    }
+
+    protected function getMessenger(): FlashMessenger
+    {
+        /** @noinspection PhpUndefinedMethodInspection */
+        /** @var FlashMessenger $messenger */
+        return $this->flashMessenger();
+    }
+
     /**
      * @noinspection PhpUnused
      * @return Response|ViewModel
      */
     public function createAction()
     {
+        /** @var Form $form */
         /** @var Request $request */
+        /** @var Select $homeLibraryElement */
         $request = $this->getRequest();
         $query = $request->getQuery();
         $messenger = $this->getMessenger();
@@ -150,21 +195,10 @@ class UserController extends AbstractBase
             return $this->redirect()->toRoute('fid/user/init');
         }
 
-        /** @var Form $form */
-        $form = $this->serviceLocator->get(UserCreateModel::class);
-
-        /** @var Select $homeLibraryElement */
-        $homeLibraryElement = $form->get('homeLibrary');
+        $form = $this->serviceLocator->get('user-create-form');
+        $homeLibraryElement = $form->get('home_library');
         $homeLibraryElement->setValueOptions($libraries);
 
-        /** @var Radio $accessLevelElement */
-        $accessLevelElement = $form->get('accessLevel');
-        $accessLevels = $this->config['Security']['access_levels'];
-        $accessLevelValueOptions = array_map(function ($accessLevel) {
-            return "label_access_level_$accessLevel";
-        }, array_combine($accessLevels, $accessLevels));
-        $accessLevelElement->setValueOptions($accessLevelValueOptions);
-
         if ($this->formWasSubmitted()) {
             $form->setData($request->getPost());
             if ($form->isValid()) {
@@ -174,6 +208,10 @@ class UserController extends AbstractBase
             $form->setData($query);
         }
 
+        $action = $this->url()->fromRoute('fid/user/create');
+        $form->setAttribute('action', $action);
+        $form->prepare();
+
         $view = $this->createViewModel();
         $view->setVariables(compact('form'));
         $view->setTemplate('fid/user/create');
@@ -181,17 +219,43 @@ class UserController extends AbstractBase
         return $view;
     }
 
+    protected function create(Form $form)
+    {
+        /** @var User $user */
+        $messenger = $this->getMessenger();
+        $user = $form->getHydrator()->hydrate($form->getData(), new User());
+
+        try {
+            $this->client->requestUserCreation($user);
+            $message = $this->translate('fid::user_create_success');
+            $messenger->addSuccessMessage($message);
+            /** @noinspection PhpParamsInspection */
+            $this->authManager->create($this->getRequest());
+        } catch (ClientException $exception) {
+            $message = $this->translate('fid::user_create_error');
+            $messenger->addErrorMessage($message);
+        } catch (AuthException $e) {
+            $message = $this->translate('fid::user_create_error_autologon');
+            $messenger->addWarningMessage($message);
+        }
+
+        return $this->redirect()->toRoute('myresearch-home', [], [
+            'query' => ['redirect' => false]
+        ]);
+    }
 
     /**
-     * @noinspection PhpUnused
      * @return Response|ViewModel
+     * @throws UserNotAuthorizedException
      */
     public function updateAction()
     {
+        /** @var Form $form */
         /** @var Request $request */
-        $request = $this->getRequest();
+        /** @var Select $homeLibraryElement */
 
         try {
+            $request = $this->getRequest();
             $user = $this->client->requestUserDetails();
             $libraries = array_map(function (Library $libary) {
                 return $libary->getLabel();
@@ -205,11 +269,8 @@ class UserController extends AbstractBase
             return $this->redirect()->toRoute('myresearch-home');
         }
 
-        /** @var Form $form */
-        $form = $this->serviceLocator->get(UserUpdateModel::class);
-
-        /** @var Select $homeLibraryElement */
-        $homeLibraryElement = $form->get('homeLibrary');
+        $form = $this->serviceLocator->get('user-update-form');
+        $homeLibraryElement = $form->get('home_library');
         $homeLibraryElement->setValueOptions($libraries);
 
         if ($this->formWasSubmitted()) {
@@ -217,15 +278,56 @@ class UserController extends AbstractBase
             if ($form->isValid()) {
                 return $this->update($form);
             }
+        } else {
+            $form->setData($form->getHydrator()->extract($user));
         }
 
+        $action = $this->url()->fromRoute('fid/user/update');
+        $form->setAttribute('action', $action);
+        $form->prepare();
+
         $viewModel = $this->createViewModel();
-        $viewModel->setVariables(compact('form', 'user'));
+        $viewModel->setVariables(compact('form'));
         $viewModel->setTemplate('fid/user/update');
 
         return $viewModel;
     }
 
+    /**
+     * @param Form   $form
+     * @param string $redirect
+     *
+     * @return Response
+     * @throws UserNotAuthorizedException
+     */
+    protected function update(Form $form, string $redirect = 'myresearch-home')
+    {
+        $data = $form->getData();
+        $messenger = $this->getMessenger();
+
+        try {
+            $user = $this->client->requestUserDetails($data['id']);
+            $form->getHydrator()->hydrate($data, $user);
+            $this->client->requestUserUpdate($user);
+            $message = $this->translate('fid::user_update_success');
+            $messenger->addSuccessMessage($message);
+        } catch (ClientException $exception) {
+            if (in_array($exception->getCode(), [403])) {
+                $message = $this->translate('fid::user_update_error_'
+                    . $exception->getCode());
+            } else {
+                $message = $this->translate('fid::user_update_error');
+            }
+
+            $messenger->addErrorMessage($message);
+        }
+
+        $this->client->flushUserList();
+        return $this->redirect()->toRoute($redirect, [], [
+            'query' => ['redirect' => false]
+        ]);
+    }
+
     /**
      * @noinspection PhpUnused
      * @return ViewModel
@@ -251,6 +353,36 @@ class UserController extends AbstractBase
         return $view;
     }
 
+    protected function changeUsername(Form $form)
+    {
+        $messenger = $this->getMessenger();
+        $model = $form->getHydrator()->hydrate(
+            $form->getData(), new UsernameChangeModel());
+
+        /** @noinspection PhpUndefinedFieldInspection */
+        $query['lng'] = $this->layout()->userLang;
+        $username = $query['username'] = $model->getUsername();
+        $baseUrl = $this->url()->fromRoute('fid/user/update-username',
+            [], ['query' => $query, 'force_canonical' => true]);
+
+        try {
+            $this->client->requestUsernameLink($baseUrl, $username);
+        } catch (ClientException $exception) {
+            $message = $exception->getCode() === 400
+                ? 'fid::username_change_error_username'
+                : 'fid::username_change_error';
+            $messenger->addErrorMessage($this->translate($message));
+            return $this->forward()->dispatch(self::class, [
+                'action'    => 'changeUsername',
+                'forwarded' => true
+            ]);
+        }
+
+        $message = $this->translate('fid::username_change_success');
+        $messenger->addSuccessMessage(sprintf($message, $username));
+        return $this->redirect()->toRoute('myresearch-home');
+    }
+
     /**
      * @noinspection PhpUnused
      * @return Response
@@ -344,6 +476,33 @@ class UserController extends AbstractBase
         return $view;
     }
 
+    protected function sendResetPassword(Form $form)
+    {
+        /** @var PasswordResetModel $model */
+        $messenger = $this->getMessenger();
+        $model = $form->getHydrator()->hydrate(
+            $form->getData(), new PasswordResetModel());
+        $username = $model->getUsername();
+
+        try {
+            /** @noinspection PhpUndefinedFieldInspection */
+            $query['lng'] = $this->layout()->userLang;
+            $baseUrl = $this->url()->fromRoute('fid/user/change-password',
+                [], ['query' => $query, 'force_canonical' => true]);
+            $this->client->requestPasswordLink($baseUrl, $username);
+            $message = $this->translate('fid::password_reset_success');
+            $messenger->addSuccessMessage(sprintf($message, $username));
+        } catch (ClientException $exception) {
+            $message = $exception->getCode() === 400
+                ? $this->translate('fid::password_reset_error_username')
+                : $this->translate('fid::password_reset_error');
+            $messenger->addErrorMessage(sprintf($message, $username));
+            return $this->redirect()->toRoute('fid/user/reset-password');
+        }
+
+        return $this->redirect()->toRoute('myresearch-home');
+    }
+
     /**
      * Reset password action - Allows the change password form to appear.
      *
@@ -391,178 +550,6 @@ class UserController extends AbstractBase
         return $view;
     }
 
-    /**
-     * @param Form $form
-     *
-     * @return mixed|Response
-     */
-    protected function init(Form $form)
-    {
-        /** @var UserInitModel $model */
-        $messenger = $this->getMessenger();
-        $model = $form->getHydrator()
-            ->hydrate($form->getData(), new UserInitModel());
-
-        /** @noinspection PhpUndefinedFieldInspection */
-        $query['lng'] = $this->layout()->userLang;
-        $username = $query['username'] = $model->getUsername();
-        $firstname = $query['firstname'] = $model->getFirstname();
-        $lastname = $query['lastname'] = $model->getLastname();
-        $baseUrl = $this->url()->fromRoute('fid/user/create',
-            [], ['query' => $query, 'force_canonical' => true]);
-
-        try {
-            $this->client->requestRegistrationLink($baseUrl, $username,
-                $firstname, $lastname);
-        } catch (ClientException $exception) {
-            $message = $exception->getCode() === 400
-                ? 'fid::user_init_error_username'
-                : 'fid::user_init_error';
-            $messenger->addErrorMessage($this->translate($message));
-            return $this->forward()->dispatch(self::class, [
-                'action'    => 'init',
-                'forwarded' => true
-            ]);
-        }
-
-        $message = $this->translate('fid::user_init_success');
-        $messenger->addSuccessMessage(sprintf($message, $username));
-        return $this->redirect()->toRoute('myresearch-home');
-    }
-
-    protected function create(Form $form)
-    {
-        $messenger = $this->getMessenger();
-        /** @var UserCreateModel $model */
-        $model = $form->getHydrator()
-            ->hydrate($form->getData(), new UserCreateModel());
-
-        $user = new User();
-        $user->setUsername($username = $model->getUsername());
-        $user->setPassword($password = $model->getPassword());
-        $user->setHomeLibrary($model->getHomeLibrary());
-        $user->setPermissions([$model->getAccessLevel() => 'requested']);
-        $user->setSalutation($model->getSalutation());
-        $user->setAcademicTitle($model->getAcademicTitle());
-        $user->setFirstname($model->getFirstname());
-        $user->setLastname($model->getLastname());
-        $user->setYearOfBirth($model->getYearOfBirth());
-        $user->setCollege($model->getCollege());
-        $user->setJobTitle($model->getJobTitle());
-
-        if ($model->getAddressLine1()) {
-            $address = new Address();
-            $address->setLine1($model->getAddressLine1());
-            $address->setLine2($model->getAddressLine2());
-            $address->setZip($model->getAddressZip());
-            $address->setCity($model->getAddressCity());
-            $address->setCountry($model->getAddressCountry());
-            $user->setAddresses([$address]);
-        }
-
-        try {
-            $this->client->requestUserCreation($user);
-            $message = $this->translate('fid::user_create_success');
-            $messenger->addSuccessMessage($message);
-            /** @noinspection PhpParamsInspection */
-            $this->authManager->create($this->getRequest());
-        } catch (ClientException $exception) {
-            $message = $this->translate('fid::user_create_error');
-            $messenger->addErrorMessage($message);
-        } catch (AuthException $e) {
-            $message = $this->translate('fid::user_create_error_autologon');
-            $messenger->addWarningMessage($message);
-        }
-
-        return $this->redirect()->toRoute('myresearch-home', [], [
-            'query' => ['redirect' => false]
-        ]);
-    }
-
-    /**
-     * @param Form $form
-     *
-     * @return Response
-     */
-    protected function update(Form $form,string $redirect = 'myresearch-home')
-    {
-        $messenger = $this->getMessenger();
-        /** @var UserUpdateModel $model */
-        $model = $form->getHydrator()->hydrate($form->getData(),
-            new UserUpdateModel());
-
-        try {
-            $userId = $model->getUserId();
-            $user = $this->client->requestUserDetails($userId);
-            $user->setHomeLibrary($model->getHomeLibrary());
-            $user->setSalutation($model->getSalutation());
-            $user->setAcademicTitle($model->getAcademicTitle());
-            $user->setFirstname($model->getFirstname());
-            $user->setLastname($model->getLastname());
-            $user->setYearOfBirth($model->getYearOfBirth());
-            $user->setCollege($model->getCollege());
-            $user->setJobTitle($model->getJobTitle());
-            $user->setPermissions($model->getPermissions());
-            $addresses = $user->getAddresses();
-            foreach ($model->getAddresses() as $index => $address) {
-                $addr = $addresses[$index] ?? new Address();
-                $addr->setLine1($address['line1']);
-                $addr->setLine2($address['line2']);
-                $addr->setZip($address['zip']);
-                $addr->setCity($address['city']);
-                $addr->setCountry($address['country']);
-                $addresses[$index] = $addr;
-            }
-            $user->setAddresses($addresses);
-            $this->client->requestUserUpdate($user);
-            $message = $this->translate('fid::user_update_success');
-            $messenger->addSuccessMessage($message);
-
-
-        } catch (ClientException $exception) {
-            if (in_array($exception->getCode(), [403])) {
-                $message = $this->translate('fid::user_update_error_'
-                    . $exception->getCode());
-            } else {
-                $message = $this->translate('fid::user_update_error');
-            }
-
-            $messenger->addErrorMessage($message);
-        }
-
-        $this->client->flushUserList();
-        return $this->redirect()->toRoute($redirect, [], [
-            'query' => ['redirect' => false]
-        ]);
-    }
-
-    protected function sendResetPassword(Form $form)
-    {
-        /** @var PasswordResetModel $model */
-        $messenger = $this->getMessenger();
-        $model = $form->getHydrator()->hydrate(
-            $form->getData(), new PasswordResetModel());
-        $username = $model->getUsername();
-
-        try {
-            /** @noinspection PhpUndefinedFieldInspection */
-            $query['lng'] = $this->layout()->userLang;
-            $baseUrl = $this->url()->fromRoute('fid/user/change-password',
-                [], ['query' => $query, 'force_canonical' => true]);
-            $this->client->requestPasswordLink($baseUrl, $username);
-            $message = $this->translate('fid::password_reset_success');
-            $messenger->addSuccessMessage(sprintf($message, $username));
-        } catch (ClientException $exception) {
-            $message = $exception->getCode() === 400
-                ? $this->translate('fid::password_reset_error_username')
-                : $this->translate('fid::password_reset_error');
-            $messenger->addErrorMessage(sprintf($message, $username));
-            return $this->redirect()->toRoute('fid/user/reset-password');
-        }
-
-        return $this->redirect()->toRoute('myresearch-home');
-    }
-
     protected function changePassword(Form $form)
     {
         /** @var PasswordChangeModel $model */
@@ -597,47 +584,9 @@ class UserController extends AbstractBase
         ]);
     }
 
-    protected function changeUsername(Form $form)
-    {
-        $messenger = $this->getMessenger();
-        $model = $form->getHydrator()->hydrate(
-            $form->getData(), new UsernameChangeModel());
-
-        /** @noinspection PhpUndefinedFieldInspection */
-        $query['lng'] = $this->layout()->userLang;
-        $username = $query['username'] = $model->getUsername();
-        $baseUrl = $this->url()->fromRoute('fid/user/update-username',
-            [], ['query' => $query, 'force_canonical' => true]);
-
-        try {
-            $this->client->requestUsernameLink($baseUrl, $username);
-        } catch (ClientException $exception) {
-            $message = $exception->getCode() === 400
-                ? 'fid::username_change_error_username'
-                : 'fid::username_change_error';
-            $messenger->addErrorMessage($this->translate($message));
-            return $this->forward()->dispatch(self::class, [
-                'action'    => 'changeUsername',
-                'forwarded' => true
-            ]);
-        }
-
-        $message = $this->translate('fid::username_change_success');
-        $messenger->addSuccessMessage(sprintf($message, $username));
-        return $this->redirect()->toRoute('myresearch-home');
-    }
-
-    protected function getMessenger(): FlashMessenger
-    {
-        /** @noinspection PhpUndefinedMethodInspection */
-        /** @var FlashMessenger $messenger */
-        return $this->flashMessenger();
-    }
-
     public function editAction()
     {
-        // Not logged in?  Force user to log in:
-        if (!($user = $this->getUser())) {
+        if (!$this->getUser()) {
             return $this->forceLogin();
         }
 
@@ -650,20 +599,24 @@ class UserController extends AbstractBase
             return $this->redirect()->toRoute('fid/admin/list');
         }
 
-        $editableFields = $this->config['Admin']['editable_user_fields'] ?? [];
-
         try {
             try {
                 $user = $this->client->requestUserDetails($userId);
             } catch (UserNotAuthorizedException $ex) {
                 // either user does not exist, or we are not allowed to edit it
-                $this->getMessenger()->addErrorMessage($this->translate('fid::user_edit_not_allowed', ['%%userid%%' => $userId]));
+                $this->getMessenger()
+                    ->addErrorMessage($this->translate('fid::user_edit_not_allowed',
+                        ['%%userid%%' => $userId]));
                 return $this->redirect()->toRoute('fid/admin/list');
             } catch (\Exception $ex) {
-                $this->getMessenger()->addErrorMessage($this->translate('fid::user_read_error',['%%userid%%' => $userId]));
+                $this->getMessenger()
+                    ->addErrorMessage($this->translate('fid::user_read_error',
+                        ['%%userid%%' => $userId]));
                 return $this->redirect()->toRoute('fid/admin/list');
             }
-            $libraries = $this->client->requestLibraryList();
+            $libraries = array_map(function (Library $libary) {
+                return $libary->getLabel();
+            }, $this->client->requestLibraryList());
         } catch (ClientException $exception) {
             $this->setFollowupUrlToReferer();
             $message = $exception->getCode() === 401
@@ -674,114 +627,57 @@ class UserController extends AbstractBase
         }
 
         /** @var Form $form */
-        $form = $this->serviceLocator->get(UserUpdateModel::class);
-
-        if (!empty($libraries)) {
-            $userLibrary = $user->getHomeLibrary();
-            $libraries = array_map(function (Library $libary) use ($editableFields,$userLibrary) {
-                $option = [
-                    'label' => $libary->getLabel(),
-                    'value' => $id = $libary->getId(),
-                    'selected' => $id == $userLibrary
-                ];
-                if ($id != $userLibrary && !in_array('HomeLibrary', $editableFields)) {
-                    $option['attributes']['disabled'] = 'disabled';
-                }
-                return $option;
-            }, $libraries);
-
-            /** @var Select $homeLibraryElement */
-            $homeLibraryElement = $form->get('homeLibrary');
-            $homeLibraryElement->setValueOptions($libraries);
-        }
-
-        if ($permissions = $this->config['Admin']['permission_options'] ?? []) {
-
-            $userPermissions = $user->getPermissions();
-            if (!isset(self::$currentPermissions)) {
-                $valid = [];
-                foreach ($permissions as $permission) {
-                    $valid[$permission] = $userPermissions[$permission] ?? 'denied';
-                }
-                self::$currentPermissions = $valid;
-            }
-            /** @var MultiCheckbox $permissionsElement */
-            $permissionsElement = $form->get('permissions');
-            $permissions = array_map(function ($permission) use ($editableFields,$userPermissions) {
-                $option = [
-                    'label' => $this->translate('fid::permission_' . $permission),
-                    'name' => $permission,
-                    'label_attributes' => ['class' => 'permission-label col-sm-11'],
-                    'attributes' => ['class' => 'permission-option col-sm-1'],
-                    'selected' => isset($userPermissions[$permission]) && $userPermissions[$permission] == 'granted',
-                    'value' => $permission . '::' . ($userPermissions[$permission] ?? 'denied'),
-                ];
-                if (!in_array('Permissions', $editableFields)) {
-                    $option['disabled'] = '1';
-                }
-                return $option;
-            }, $permissions);
-            $permissionsElement->setDisableInArrayValidator(true);
-            $permissionsElement->setValueOptions($permissions);
-        }
+        /** @var Select $homeLibraryElement */
+        $form = $this->serviceLocator->get('admin-edit-form');
+        $homeLibraryElement = $form->get('home_library');
+        $homeLibraryElement->setValueOptions($libraries);
+        $homeLibraryElement->setUnselectedValue($user->getHomeLibrary());
 
         if ($this->formWasSubmitted()) {
             $form->setData($request->getPost());
             if ($form->isValid()) {
-                return $this->update($form,'fid/admin/list');
+                return $this->update($form, 'fid/admin/list');
             }
+        } else {
+            $form->setData($form->getHydrator()->extract($user));
         }
 
+        $action = $this->url()->fromRoute('fid/admin/edit', [
+            'userid' => $userId
+        ]);
+        $form->setAttribute('action', $action);
+        $form->prepare();
+
+        $config = $this->config;
         $viewModel = $this->createViewModel();
-        $viewModel->setVariables(compact('form', 'user','editableFields'));
+        $viewModel->setVariables(compact('config', 'form', 'user'));
         $viewModel->setTemplate('fid/admin/edit');
 
         return $viewModel;
     }
 
-    public static $currentPermissions;
-
-    public static function combinePermissionsArray($input) {
-        if (empty($input)) {
-            return [];
-        }
-
-        $output = [];
-        foreach ($input as $line) {
-            list($key,) = explode('::',$line);
-            if (isset(self::$currentPermissions[$key])) {
-                $output[$key] = 'granted';
-            }
-        }
-        foreach (self::$currentPermissions as $key => $state) {
-            if ($state === 'granted' && !isset($output[$key])) {
-                $output[$key] = 'denied';
-            }
-        }
-        return array_intersect_key($output,['full_access'=>'0','limited_access'=>1]);
-    }
-
-    public function listAction() {
-
-        // Not logged in?  Force user to log in:
-        if (!($user = $this->getUser())) {
+    public function listAction()
+    {
+        if (!$this->getUser()) {
             return $this->forceLogin();
         }
 
         $viewModel = $this->createViewModel();
         try {
             $list = $this->client->requestUserList();
-            $viewModel->setVariable('list',$list);
+            $viewModel->setVariable('list', $list);
         } catch (UserNotAuthorizedException $exception) {
-            $this->getMessenger()->addErrorMessage('fid::read_user_list_not_allowed');
+            $this->getMessenger()
+                ->addErrorMessage('fid::read_user_list_not_allowed');
         } catch (ClientException $exception) {
             $this->getMessenger()->addErrorMessage('fid::read_user_list_error');
         }
 
         if ($fields = $this->config['Admin']['overview_fields']) {
-            $viewModel->setVariable('fields',$fields);
+            $viewModel->setVariable('fields', $fields);
         }
 
+        $viewModel->setVariable('config', $this->config);
         $viewModel->setTemplate('fid/admin/list');
         return $viewModel;
     }
diff --git a/module/fid/src/FormModel/UserCreateModel.php b/module/fid/src/FormModel/UserCreateModel.php
deleted file mode 100644
index 1ddbc526dad894899e173a372a67d1949c456284..0000000000000000000000000000000000000000
--- a/module/fid/src/FormModel/UserCreateModel.php
+++ /dev/null
@@ -1,426 +0,0 @@
-<?php
-/**
- * Copyright (C) 2019 Leipzig University Library
- *
- * 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.
- *
- * @author   Gregor Gawol <gawol@ub.uni-leipzig.de>
- * @author   Sebastian Kehr <kehr@ub.uni-leipzig.de>
- * @license  http://opensource.org/licenses/gpl-2.0.php GNU GPLv2
- */
-
-namespace fid\FormModel;
-
-class UserCreateModel
-{
-    /**
-     * @var string
-     */
-    protected $username;
-
-    /**
-     * @var string
-     */
-    protected $password;
-
-    /**
-     * @var string
-     */
-    protected $passwordConfirmation;
-
-    /**
-     * @var string
-     */
-    protected $salutation;
-
-    /**
-     * @var string
-     */
-    protected $academicTitle;
-
-    /**
-     * @var string
-     */
-    protected $firstname;
-
-    /**
-     * @var string
-     */
-    protected $lastname;
-
-    /**
-     * @var string
-     */
-    protected $homeLibrary;
-
-    /**
-     * @var string
-     */
-    protected $accessLevel;
-
-    /**
-     * @var int|null
-     */
-    protected $yearOfBirth;
-
-    /**
-     * @var string
-     */
-    protected $jobTitle;
-
-    /**
-     * @var string
-     */
-    protected $college;
-
-    /**
-     * @var string
-     */
-    protected $addressLine1;
-
-    /**
-     * @var string
-     */
-    protected $addressLine2;
-
-    /**
-     * @var string
-     */
-    protected $addressZip;
-
-    /**
-     * @var string
-     */
-    protected $addressCity;
-
-    /**
-     * @var string
-     */
-    protected $addressCountry;
-
-    /**
-     * @var bool
-     */
-    protected $eulaAccepted;
-
-    /**
-     * @var string
-     */
-    protected $submit;
-
-    /**
-     * @return string
-     */
-    public function getUsername(): string
-    {
-        return $this->username;
-    }
-
-    /**
-     * @param string $username
-     */
-    public function setUsername(string $username): void
-    {
-        $this->username = $username;
-    }
-
-    /**
-     * @return string
-     */
-    public function getFirstname(): string
-    {
-        return $this->firstname;
-    }
-
-    /**
-     * @param string $firstname
-     */
-    public function setFirstname(string $firstname): void
-    {
-        $this->firstname = $firstname;
-    }
-
-    /**
-     * @return string
-     */
-    public function getLastname(): string
-    {
-        return $this->lastname;
-    }
-
-    /**
-     * @param string $lastname
-     */
-    public function setLastname(string $lastname): void
-    {
-        $this->lastname = $lastname;
-    }
-
-    /**
-     * @return string
-     */
-    public function getSalutation(): string
-    {
-        return $this->salutation;
-    }
-
-    /**
-     * @param string $salutation
-     */
-    public function setSalutation(string $salutation): void
-    {
-        $this->salutation = $salutation;
-    }
-
-    /**
-     * @return string
-     */
-    public function getAcademicTitle(): string
-    {
-        return $this->academicTitle;
-    }
-
-    /**
-     * @param string $academicTitle
-     */
-    public function setAcademicTitle(string $academicTitle): void
-    {
-        $this->academicTitle = $academicTitle;
-    }
-
-    /**
-     * @return string
-     */
-    public function getHomeLibrary(): string
-    {
-        return $this->homeLibrary;
-    }
-
-    /**
-     * @param string $homeLibrary
-     */
-    public function setHomeLibrary(string $homeLibrary): void
-    {
-        $this->homeLibrary = $homeLibrary;
-    }
-
-    /**
-     * @return int|null
-     */
-    public function getYearOfBirth(): ?int
-    {
-        return $this->yearOfBirth;
-    }
-
-    /**
-     * @param int|null $yearOfBirth
-     */
-    public function setYearOfBirth(?int $yearOfBirth): void
-    {
-        $this->yearOfBirth = $yearOfBirth;
-    }
-
-
-    /**
-     * @return string
-     */
-    public function getAccessLevel(): string
-    {
-        return $this->accessLevel;
-    }
-
-    /**
-     * @param string $accessLevel
-     */
-    public function setAccessLevel(string $accessLevel): void
-    {
-        $this->accessLevel = $accessLevel;
-    }
-
-    /**
-     * @return bool
-     */
-    public function isEulaAccepted(): bool
-    {
-        return $this->eulaAccepted;
-    }
-
-    /**
-     * @param bool $eulaAccepted
-     */
-    public function setEulaAccepted(bool $eulaAccepted): void
-    {
-        $this->eulaAccepted = $eulaAccepted;
-    }
-
-    /**
-     * @return string
-     */
-    public function getSubmit(): string
-    {
-        return $this->submit;
-    }
-
-    /**
-     * @param string $submit
-     */
-    public function setSubmit(string $submit): void
-    {
-        $this->submit = $submit;
-    }
-
-    /**
-     * @return string
-     */
-    public function getJobTitle(): string
-    {
-        return $this->jobTitle;
-    }
-
-    /**
-     * @param string $jobTitle
-     */
-    public function setJobTitle(string $jobTitle): void
-    {
-        $this->jobTitle = $jobTitle;
-    }
-
-    /**
-     * @return string
-     */
-    public function getCollege(): string
-    {
-        return $this->college;
-    }
-
-    /**
-     * @param string $college
-     */
-    public function setCollege(string $college): void
-    {
-        $this->college = $college;
-    }
-
-    /**
-     * @return string
-     */
-    public function getPassword(): string
-    {
-        return $this->password;
-    }
-
-    /**
-     * @param string $password
-     */
-    public function setPassword(string $password): void
-    {
-        $this->password = $password;
-    }
-
-    /**
-     * @return string
-     */
-    public function getPasswordConfirmation(): string
-    {
-        return $this->passwordConfirmation;
-    }
-
-    /**
-     * @param string $passwordConfirmation
-     */
-    public function setPasswordConfirmation(string $passwordConfirmation): void
-    {
-        $this->passwordConfirmation = $passwordConfirmation;
-    }
-
-    /**
-     * @return string
-     */
-    public function getAddressLine1(): string
-    {
-        return $this->addressLine1;
-    }
-
-    /**
-     * @param string $addressLine1
-     */
-    public function setAddressLine1(string $addressLine1): void
-    {
-        $this->addressLine1 = $addressLine1;
-    }
-
-    /**
-     * @return string
-     */
-    public function getAddressLine2(): string
-    {
-        return $this->addressLine2;
-    }
-
-    /**
-     * @param string $addressLine2
-     */
-    public function setAddressLine2(string $addressLine2): void
-    {
-        $this->addressLine2 = $addressLine2;
-    }
-
-    /**
-     * @return string
-     */
-    public function getAddressZip(): string
-    {
-        return $this->addressZip;
-    }
-
-    /**
-     * @param string $addressZip
-     */
-    public function setAddressZip(string $addressZip): void
-    {
-        $this->addressZip = $addressZip;
-    }
-
-    /**
-     * @return string
-     */
-    public function getAddressCity(): string
-    {
-        return $this->addressCity;
-    }
-
-    /**
-     * @param string $addressCity
-     */
-    public function setAddressCity(string $addressCity): void
-    {
-        $this->addressCity = $addressCity;
-    }
-
-    /**
-     * @return string
-     */
-    public function getAddressCountry(): string
-    {
-        return $this->addressCountry;
-    }
-
-    /**
-     * @param string $addressCountry
-     */
-    public function setAddressCountry(string $addressCountry): void
-    {
-        $this->addressCountry = $addressCountry;
-    }
-}
diff --git a/module/fid/src/FormModel/UserInitModel.php b/module/fid/src/FormModel/UserInitModel.php
deleted file mode 100644
index 6d48255e633f5a55cced7f8c63386a1c37ff30d2..0000000000000000000000000000000000000000
--- a/module/fid/src/FormModel/UserInitModel.php
+++ /dev/null
@@ -1,152 +0,0 @@
-<?php
-/**
- * Copyright (C) 2019 Leipzig University Library
- *
- * 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.
- *
- * @author   Gregor Gawol <gawol@ub.uni-leipzig.de>
- * @author   Sebastian Kehr <kehr@ub.uni-leipzig.de>
- * @license  http://opensource.org/licenses/gpl-2.0.php GNU GPLv2
- */
-
-namespace fid\FormModel;
-
-class UserInitModel
-{
-    /**
-     * @var string
-     */
-    protected $username;
-
-    /**
-     * @var string
-     */
-    protected $usernameConfirmation;
-
-    /**
-     * @var string
-     */
-    protected $firstname;
-
-    /**
-     * @var string
-     */
-    protected $lastname;
-
-    /**
-     * @var bool
-     */
-    protected $eulaAccepted;
-
-    /**
-     * @var string
-     */
-    protected $submit;
-
-    /**
-     * @return string
-     */
-    public function getUsername(): string
-    {
-        return $this->username;
-    }
-
-    /**
-     * @param string $username
-     */
-    public function setUsername(string $username): void
-    {
-        $this->username = $username;
-    }
-
-    /**
-     * @return string
-     */
-    public function getUsernameConfirmation(): string
-    {
-        return $this->usernameConfirmation;
-    }
-
-    /**
-     * @param string $usernameConfirmation
-     */
-    public function setUsernameConfirmation(string $usernameConfirmation): void
-    {
-        $this->usernameConfirmation = $usernameConfirmation;
-    }
-
-    /**
-     * @return string
-     */
-    public function getFirstname(): string
-    {
-        return $this->firstname;
-    }
-
-    /**
-     * @param string $firstname
-     */
-    public function setFirstname(string $firstname): void
-    {
-        $this->firstname = $firstname;
-    }
-
-    /**
-     * @return string
-     */
-    public function getLastname(): string
-    {
-        return $this->lastname;
-    }
-
-    /**
-     * @param string $lastname
-     */
-    public function setLastname(string $lastname): void
-    {
-        $this->lastname = $lastname;
-    }
-
-    /**
-     * @return bool
-     */
-    public function isEulaAccepted(): bool
-    {
-        return $this->eulaAccepted;
-    }
-
-    /**
-     * @param bool $eulaAccepted
-     */
-    public function setEulaAccepted(bool $eulaAccepted): void
-    {
-        $this->eulaAccepted = $eulaAccepted;
-    }
-
-    /**
-     * @return string
-     */
-    public function getSubmit(): string
-    {
-        return $this->submit;
-    }
-
-    /**
-     * @param string $submit
-     */
-    public function setSubmit(string $submit): void
-    {
-        $this->submit = $submit;
-    }
-}
diff --git a/module/fid/src/FormModel/UserUpdateModel.php b/module/fid/src/FormModel/UserUpdateModel.php
deleted file mode 100644
index 6366da868a461ce38c818f76c6acffa12c669eda..0000000000000000000000000000000000000000
--- a/module/fid/src/FormModel/UserUpdateModel.php
+++ /dev/null
@@ -1,278 +0,0 @@
-<?php
-/**
- * Copyright (C) 2019 Leipzig University Library
- *
- * 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.
- *
- * @author   Gregor Gawol <gawol@ub.uni-leipzig.de>
- * @author   Sebastian Kehr <kehr@ub.uni-leipzig.de>
- * @license  http://opensource.org/licenses/gpl-2.0.php GNU GPLv2
- */
-
-namespace fid\FormModel;
-
-class UserUpdateModel
-{
-    /**
-     * @var string
-     */
-    protected $userId;
-
-    /**
-     * @var string
-     */
-    protected $salutation;
-
-    /**
-     * @var string
-     */
-    protected $academicTitle;
-
-    /**
-     * @var string
-     */
-    protected $firstname;
-
-    /**
-     * @var string
-     */
-    protected $lastname;
-
-    /**
-     * @var string
-     */
-    protected $homeLibrary;
-
-    /**
-     * @var int|null
-     */
-    protected $yearOfBirth;
-
-    /**
-     * @var string
-     */
-    protected $jobTitle;
-
-    /**
-     * @var string
-     */
-    protected $college;
-
-    /**
-     * @var string[][]
-     */
-    protected $addresses = [];
-
-    /**
-     * @var array
-     */
-    protected $permissions;
-
-    /**
-     * @var string|null
-     */
-    protected $submit;
-
-    /**
-     * @return string|null
-     */
-    public function getUserId(): ?string
-    {
-        return $this->userId;
-    }
-
-    /**
-     * @param string $userId
-     */
-    public function setUserId(string $userId = null): void
-    {
-        $this->userId = $userId;
-    }
-
-    /**
-     * @return string
-     */
-    public function getSalutation(): ?string
-    {
-        return $this->salutation;
-    }
-
-    /**
-     * @param string $salutation
-     */
-    public function setSalutation(string $salutation): void
-    {
-        $this->salutation = $salutation;
-    }
-
-    /**
-     * @return string|null
-     */
-    public function getAcademicTitle(): ?string
-    {
-        return $this->academicTitle;
-    }
-
-    /**
-     * @param string $academicTitle
-     */
-    public function setAcademicTitle(string $academicTitle): void
-    {
-        $this->academicTitle = $academicTitle;
-    }
-
-    /**
-     * @return string
-     */
-    public function getFirstname(): string
-    {
-        return $this->firstname;
-    }
-
-    /**
-     * @param string $firstname
-     */
-    public function setFirstname(string $firstname): void
-    {
-        $this->firstname = $firstname;
-    }
-
-    /**
-     * @return string
-     */
-    public function getLastname(): string
-    {
-        return $this->lastname;
-    }
-
-    /**
-     * @param string $lastname
-     */
-    public function setLastname(string $lastname): void
-    {
-        $this->lastname = $lastname;
-    }
-
-    /**
-     * @return string
-     */
-    public function getHomeLibrary(): string
-    {
-        return $this->homeLibrary;
-    }
-
-    /**
-     * @param string $homeLibrary
-     */
-    public function setHomeLibrary(string $homeLibrary): void
-    {
-        $this->homeLibrary = $homeLibrary;
-    }
-
-    /**
-     * @return int|null
-     */
-    public function getYearOfBirth(): ?int
-    {
-        return $this->yearOfBirth;
-    }
-
-    /**
-     * @param int|null $yearOfBirth
-     */
-    public function setYearOfBirth(?int $yearOfBirth): void
-    {
-        $this->yearOfBirth = $yearOfBirth;
-    }
-
-    /**
-     * @return string
-     */
-    public function getJobTitle(): string
-    {
-        return $this->jobTitle;
-    }
-
-    /**
-     * @param string $jobTitle
-     */
-    public function setJobTitle(string $jobTitle): void
-    {
-        $this->jobTitle = $jobTitle;
-    }
-
-    /**
-     * @return string
-     */
-    public function getCollege(): string
-    {
-        return $this->college;
-    }
-
-    /**
-     * @param string $college
-     */
-    public function setCollege(string $college): void
-    {
-        $this->college = $college;
-    }
-
-    /**
-     * @return string[]
-     */
-    public function getAddresses(): array
-    {
-        return $this->addresses;
-    }
-
-    /**
-     * @param string[] $addresses
-     */
-    public function setAddresses(array $addresses): void
-    {
-        $this->addresses = $addresses;
-    }
-
-    /**
-     * @param array $permissions
-     */
-    public function setPermissions(array $permissions): void
-    {
-        $this->permissions = $permissions;
-    }
-
-    /**
-     * @return array
-     */
-    public function getPermissions(): array
-    {
-        return $this->permissions;
-    }
-
-    /**
-     * @return string|null
-     */
-    public function getSubmit(): ?string
-    {
-        return $this->submit;
-    }
-
-    /**
-     * @param string|null $submit
-     */
-    public function setSubmit(?string $submit): void
-    {
-        $this->submit = $submit;
-    }
-}
diff --git a/module/fid/src/Helper/FormLabel.php b/module/fid/src/Helper/FormLabel.php
index 2517f6a50eaa112d0a9105eb51b0d70d944f4ae8..90c3b067e00bc969c739d5edb73b1f5eb255391f 100644
--- a/module/fid/src/Helper/FormLabel.php
+++ b/module/fid/src/Helper/FormLabel.php
@@ -29,9 +29,13 @@ class FormLabel extends Base
 {
     public function openTag($element = null)
     {
-        if ($element instanceof Element && $element->getAttribute('required')) {
-            $element->setLabelAttributes(['data-required' => null]
-                + $element->getLabelAttributes());
+        if ($element instanceof Element) {
+            $element->setLabelAttributes([
+                    'data-type'     => $element->getAttribute('type'),
+                    'data-name'     => $element->getAttribute('name'),
+                    'data-required' => $element->getAttribute('required')
+                        ? 'true' : 'false'
+                ] + $element->getLabelAttributes());
         }
 
         return parent::openTag($element);
diff --git a/module/fid/src/Hydrator/Strategy/UserDataStrategy.php b/module/fid/src/Hydrator/Strategy/UserDataStrategy.php
new file mode 100644
index 0000000000000000000000000000000000000000..0195938ebcdfa2bb8ece5abf8256f4390dc9de16
--- /dev/null
+++ b/module/fid/src/Hydrator/Strategy/UserDataStrategy.php
@@ -0,0 +1,67 @@
+<?php
+/**
+ * Copyright (C) 2019 Leipzig University Library
+ *
+ * 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.
+ *
+ * @author   Gregor Gawol <gawol@ub.uni-leipzig.de>
+ * @author   Sebastian Kehr <kehr@ub.uni-leipzig.de>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU GPLv2
+ */
+
+namespace fid\Hydrator\Strategy;
+
+use Zend\Hydrator\NamingStrategy\NamingStrategyInterface;
+use Zend\Hydrator\Strategy\StrategyInterface;
+
+class UserDataStrategy implements StrategyInterface
+{
+    /**
+     * @var NamingStrategyInterface
+     */
+    protected $namingStrategy;
+
+    public function __construct(NamingStrategyInterface $namingStrategy)
+    {
+        $this->namingStrategy = $namingStrategy;
+    }
+
+    public function extract($value)
+    {
+        if (!is_array($value)) {
+            return $value;
+        }
+
+        foreach ($value as $key => $val) {
+            $name = $this->namingStrategy->extract($key);
+            $result[$name] = $this->extract($val);
+        }
+
+        return $result ?? [];
+    }
+
+    public function hydrate($value)
+    {
+        if (!is_array($value)) {
+            return $value;
+        }
+
+        foreach ($value as $key => $val) {
+            $name = $this->namingStrategy->hydrate($key);
+            $result[$name] = $this->hydrate($val);
+        }
+
+        return $result;
+    }
+}
\ No newline at end of file
diff --git a/module/fid/src/Hydrator/UserHydrator.php b/module/fid/src/Hydrator/UserHydrator.php
new file mode 100644
index 0000000000000000000000000000000000000000..264dfe9cdb2a235206e669e6aa9535036ccfdc41
--- /dev/null
+++ b/module/fid/src/Hydrator/UserHydrator.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * Copyright (C) 2019 Leipzig University Library
+ *
+ * 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.
+ *
+ * @author   Gregor Gawol <gawol@ub.uni-leipzig.de>
+ * @author   Sebastian Kehr <kehr@ub.uni-leipzig.de>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU GPLv2
+ */
+
+namespace fid\Hydrator;
+
+use Zend\Hydrator\ClassMethods;
+
+class UserHydrator extends ClassMethods
+{
+}
diff --git a/module/fid/src/Hydrator/UserHydratorDelegatorFactory.php b/module/fid/src/Hydrator/UserHydratorDelegatorFactory.php
new file mode 100644
index 0000000000000000000000000000000000000000..823d81475692e03ba95c2a8df0f65ac107cd2859
--- /dev/null
+++ b/module/fid/src/Hydrator/UserHydratorDelegatorFactory.php
@@ -0,0 +1,49 @@
+<?php
+/**
+ * Copyright (C) 2019 Leipzig University Library
+ *
+ * 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.
+ *
+ * @author   Gregor Gawol <gawol@ub.uni-leipzig.de>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU GPLv2
+ */
+
+namespace fid\Hydrator;
+
+use fid\Hydrator\Strategy\UserDataStrategy;
+use fid\Service\DataTransferObject\Address;
+use Interop\Container\ContainerInterface;
+use Zend\Hydrator\AbstractHydrator;
+use Zend\Hydrator\ClassMethods;
+use Zend\Hydrator\Strategy\CollectionStrategy;
+use Zend\ServiceManager\Factory\DelegatorFactoryInterface;
+
+class UserHydratorDelegatorFactory implements DelegatorFactoryInterface
+{
+    public function __invoke(
+        ContainerInterface $container,
+        $name,
+        callable $callback,
+        array $options = null
+    ) {
+        /** @var AbstractHydrator $hydrator */
+        $hydrator = call_user_func($callback);
+        $namingStrategy = $hydrator->getNamingStrategy();
+        $hydrator->addStrategy('data', new UserDataStrategy($namingStrategy));
+        $strategy = new CollectionStrategy(new ClassMethods(), Address::class);
+        $hydrator->addStrategy('addresses', $strategy);
+
+        return $hydrator;
+    }
+}
diff --git a/module/fid/src/FormModel/AddressValidator.php b/module/fid/src/InputFilter/RootAwareBaseInputFilter.php
similarity index 65%
rename from module/fid/src/FormModel/AddressValidator.php
rename to module/fid/src/InputFilter/RootAwareBaseInputFilter.php
index 32c518eea81e09758c5cfebed46c2c6bd2d1c62f..193dd8809ee8f5a2d127c834d02bfafdf77d18b9 100644
--- a/module/fid/src/FormModel/AddressValidator.php
+++ b/module/fid/src/InputFilter/RootAwareBaseInputFilter.php
@@ -19,21 +19,19 @@
  * @license http://opensource.org/licenses/gpl-2.0.php GNU GPLv2
  */
 
-namespace fid\FormModel;
+namespace fid\InputFilter;
 
-class AddressValidator
+use Zend\InputFilter\BaseInputFilter;
+
+class RootAwareBaseInputFilter extends BaseInputFilter
 {
-    public static function init($value, $data): bool
-    {
-        return $data['addressLine1'] . $data['addressLine2']
-            . $data['addressZip'] . $data['addressCity']
-            . $data['addressCountry'] === ''
-            || $value !== '';
-    }
+    public const ROOT = '__ROOT__';
 
-    public static function validate($value, $data): bool
+    public function isValid($context = null)
     {
-        unset($data['id']);
-        return implode('', $data) === '' || $value !== '';
+        $values = array_merge($this->getRawValues(), (array)$this->data);
+        $values[self::ROOT] = $context[self::ROOT] ?? $this;
+
+        return parent::isValid($values);
     }
-}
+}
\ No newline at end of file
diff --git a/module/fid/src/Service/DataTransferObject/User.php b/module/fid/src/Service/DataTransferObject/User.php
index e7cc1bfc025370279a619e67d4bc94217c89b3d8..c356638faa370f7e641fc806e25097eb90f557f1 100644
--- a/module/fid/src/Service/DataTransferObject/User.php
+++ b/module/fid/src/Service/DataTransferObject/User.php
@@ -106,7 +106,7 @@ class User
     protected $lastname;
 
     /**
-     * @var null|int
+     * @var null|string
      * @Groups({
      *     "user:details:response",
      *     "user:creation:request",
@@ -115,10 +115,10 @@ class User
      *     "user:update:response"
      * })
      */
-    protected $yearOfBirth;
+    protected $homeLibrary;
 
     /**
-     * @var null|string
+     * @var string
      * @Groups({
      *     "user:details:response",
      *     "user:creation:request",
@@ -127,7 +127,7 @@ class User
      *     "user:update:response"
      * })
      */
-    protected $homeLibrary;
+    protected $college = '';
 
     /**
      * @var string
@@ -139,10 +139,10 @@ class User
      *     "user:update:response"
      * })
      */
-    protected $college;
+    protected $jobTitle = '';
 
     /**
-     * @var string
+     * @var Address[]
      * @Groups({
      *     "user:details:response",
      *     "user:creation:request",
@@ -151,10 +151,10 @@ class User
      *     "user:update:response"
      * })
      */
-    protected $jobTitle;
+    protected $addresses = [];
 
     /**
-     * @var Address[]
+     * @var array[]
      * @Groups({
      *     "user:details:response",
      *     "user:creation:request",
@@ -163,10 +163,10 @@ class User
      *     "user:update:response"
      * })
      */
-    protected $addresses = [];
+    protected $permissions = [];
 
     /**
-     * @var array[]
+     * @var array
      * @Groups({
      *     "user:details:response",
      *     "user:creation:request",
@@ -175,7 +175,7 @@ class User
      *     "user:update:response"
      * })
      */
-    protected $permissions = [];
+    protected $data = [];
 
     /**
      * Magic function as shortcut for all getters
@@ -304,24 +304,6 @@ class User
         $this->lastname = $lastname;
     }
 
-
-    /**
-     * @return int|null
-     */
-    public function getYearOfBirth(): ?int
-    {
-        return $this->yearOfBirth;
-    }
-
-
-    /**
-     * @param int|null $yearOfBirth
-     */
-    public function setYearOfBirth(?int $yearOfBirth): void
-    {
-        $this->yearOfBirth = $yearOfBirth;
-    }
-
     /**
      * @return string
      */
@@ -415,4 +397,20 @@ class User
         }
         return false;
     }
+
+    /**
+     * @return array
+     */
+    public function getData(): array
+    {
+        return $this->data;
+    }
+
+    /**
+     * @param array $data
+     */
+    public function setData(array $data): void
+    {
+        $this->data = $data;
+    }
 }
diff --git a/module/fid/src/VuFind/Auth/ILSAuthenticator.php b/module/fid/src/VuFind/Auth/ILSAuthenticator.php
index 5f342a0349b714f0c193b2669c6fb071b07a1105..8ccc5c2d07e2f0876af02a5386e1431482ba43b0 100644
--- a/module/fid/src/VuFind/Auth/ILSAuthenticator.php
+++ b/module/fid/src/VuFind/Auth/ILSAuthenticator.php
@@ -24,6 +24,7 @@ namespace fid\VuFind\Auth;
 use fid\Service\Client;
 use fid\Service\ClientException;
 use fid\Service\DataTransferObject\Address;
+use fid\Service\UserNotAuthorizedException;
 
 class ILSAuthenticator
 {
@@ -40,11 +41,23 @@ class ILSAuthenticator
     /**
      * @return array|null
      * @throws ClientException
+     * @throws UserNotAuthorizedException
+     */
+    public function newCatalogLogin()
+    {
+        return $this->storedCatalogLogin();
+    }
+
+    /**
+     * @return array|null
+     * @throws ClientException
+     * @throws UserNotAuthorizedException
      */
     public function storedCatalogLogin()
     {
         try {
             $user = $this->client->requestUserDetails();
+            $libs = $this->client->requestLibraryList();
         } catch (ClientException $e) {
             if ($e->getCode() == '401') {
                 return null;
@@ -62,7 +75,8 @@ class ILSAuthenticator
             'firstname'   => $user->getFirstname(),
             'lastname'    => $user->getLastname(),
             'email'       => $user->getUsername(),
-            'user'        => $user
+            'user'        => $user,
+            'libs'        => $libs,
         ];
 
         foreach ($user->getAddresses() as $index => $address) {
diff --git a/themes/fid/languages/fid/de.ini b/themes/fid/languages/fid/de.ini
index ea754dd28ad75bdb1d87a43a782cef158925c98a..171ada33fdf9e9be0cd3dd4f92dd148abbb1caca 100644
--- a/themes/fid/languages/fid/de.ini
+++ b/themes/fid/languages/fid/de.ini
@@ -22,6 +22,7 @@ label_home_library = "Heimatbibliothek"
 label_year_of_birth = "Geburtsjahr"
 label_job_title = "Berufsbezeichnung"
 label_college = "Hochschule"
+label_phone = Telefon
 label_password = "Passwort"
 label_password_confirmation = "Passwort wiederholen"
 label_access_level = "Ich gehöre folgender Nutzergruppe an"
@@ -30,7 +31,11 @@ label_access_level_limited_access = "Studierende, Sonstige"
 label_access_level_read_user_list = "Nutzerverwaltung: Nutzerliste lesen"
 label_access_level_edit_user = "Nutzerverwaltung: Nutzerprofile bearbeiten"
 label_access_level_unknown = "Unbekannte oder unbestätigte Gruppe(n)."
-label_permissions = "autorisiert für"
+label_permissions = "Zugriffsstatus"
+
+permission_status_denied = verwehrt
+permission_status_requested = angefragt
+permission_status_granted = bewilligt
 
 label_delivery_address = "Privatadresse als Lieferadresse verwenden"
 Business = "Dienstadresse"
@@ -41,13 +46,12 @@ label_address_zip = "Postleitzahl"
 label_address_city = "Ort"
 label_address_country = "Land"
 label_submit = "Abschicken"
+label_update_submit = Ändern
 terms = "Nutzungsbedingungen"
 policy = "Datenschutzerklärung"
 policy_text = "Ich akzeptiere die "
 terms_text = " und die "
 
-error_empty_address_value = "Dieser Wert wird benötigt, wenn Sie ein Adresse angeben wollen."
-
 error_username = "Bitte geben Sie eine E-Mail-Adresse an."
 error_username_confirmation = "Die angegebenen Email-Adressen stimmen nicht überein."
 error_password_confirmation = "Die angegebenen Passwörter stimmen nicht überein."
@@ -107,4 +111,4 @@ permission_edit_user = "Daten anderer Nutzer bearbeiten"
 permission_full_access = "Zugriff auf FID-Lizenzen"
 permission_limited_access = "Einfacher Zugriff"
 
-admin_section = "Nutzerverwaltung"
\ No newline at end of file
+admin_section = "Nutzerverwaltung"
diff --git a/themes/fid/languages/fid/en.ini b/themes/fid/languages/fid/en.ini
index 505dac4030f48d7fdbb87dbbd231e40b43a53972..46d63548cf7202750593e4e766ace96c9c8b0533 100644
--- a/themes/fid/languages/fid/en.ini
+++ b/themes/fid/languages/fid/en.ini
@@ -24,13 +24,18 @@ label_home_library = "Home library"
 label_year_of_birth = "Year of birth (YYYY)"
 label_job_title = "Occupation"
 label_college = "University"
+label_phone = Phone
 label_access_level = "Please select your membership level"
 label_access_level_full_access = "Professor, Research Associate/Assistant, Member of an Academic Association, PhD Student (also Scholarships), (Visiting) Lecturer"
 label_access_level_limited_access = "Student, Other"
 label_access_level_read_user_list = "User Administration: Read User List"
 label_access_level_edit_user = "User Administration: Edit User Profiles"
 label_access_level_unknown = "Unknown or ungranted user group(s)."
-label_permissions = "authorized for"
+label_permissions = "Access status"
+
+permission_status_denied = denied
+permission_status_requested = requested
+permission_status_granted = granted
 
 label_delivery_address = "Use the following address for deliveries"
 Business = "Office Address"
@@ -41,13 +46,12 @@ label_address_zip = "Zip code"
 label_address_city = "City"
 label_address_country = "Country"
 label_submit = "Submit"
+label_update_submit = Change
 terms = "Terms of Use"
 policy = "Privacy Policy"
 policy_text = "I hereby accept the "
 terms_text = " and "
 
-error_empty_address_value = "This field is required in case you want to provide an address."
-
 error_username = "Please specify an email address."
 error_username_confirmation = "The email addresses do not match."
 error_password_confirmation = "The passwords do not match."
@@ -106,4 +110,4 @@ permission_edit_user = "Edit other user's data"
 permission_full_access = "privileged access"
 permission_limited_access = "basic access"
 
-admin_section = "User Administration"
\ No newline at end of file
+admin_section = "User Administration"
diff --git a/themes/fid/scss/compiled.scss b/themes/fid/scss/compiled.scss
index 83fbd068b2e3550e225d45042b09adcd10fe9410..e0f26bee370a54254ebd87113f4c13885ce2b7c8 100644
--- a/themes/fid/scss/compiled.scss
+++ b/themes/fid/scss/compiled.scss
@@ -18,68 +18,16 @@
 @import 'customVariables';
 @import 'customMixins';
 
-.fid-user-create-form {
-  padding: 10px 0;
-
-  h2 {
-    padding-bottom: 10px;
-  }
-
-  .form-control {
-    margin: 0;
-  }
-
-  .form-group {
-    & > .col-md-4, .col-md-6, .col-md-8, .col-md-10 {
-      padding: 0;
-    }
-
-    &:after {
-      display: table;
-      content: " ";
-      clear: both;
-    }
-
-    &.eula > :first-child * {
-      display: inline;
-    }
-  }
-
-  input[type=checkbox] {
-    margin-top: 0;
-    margin-right: 10px;
-    vertical-align: middle;
-    display: inline-block;
-  }
-
-  input[type=radio] {
-    margin-top: 0;
-    margin-right: 10px;
-    vertical-align: middle;
-    display: inline-block;
-  }
-
-  label.col-md-4,
-  label[for=eulaAccepted],
-  .col-md-4 > label {
-    &[data-required]::after {
-      content: ' *';
-    }
-  }
-}
-
-.fid-user-init-form {
-  label[data-required]::after {
-    content: ' *';
-  }
-}
-
-.registration {
+#user-init-form, #user-create-form, #user-update-form {
   input[type="checkbox"] {
     display: inline-flex;
     margin-right: $margin-right-width;
     padding-left: $margin-right-width;
   }
+
+  label[data-required="true"][for]::after {
+    content: ' *';
+  }
 }
 
 .permission-options {
diff --git a/themes/fid/templates/fid/admin/edit.phtml b/themes/fid/templates/fid/admin/edit.phtml
index ef46743db675a7b319d20895342e2c86223a6260..81cc338eaf41898ad6c5798bd92d1ae877389f45 100644
--- a/themes/fid/templates/fid/admin/edit.phtml
+++ b/themes/fid/templates/fid/admin/edit.phtml
@@ -20,214 +20,190 @@
  * @license  http://opensource.org/licenses/gpl-2.0.php GNU GPLv2
  */
 
-use fid\Service\DataTransferObject\User;
 use Zend\Form\Element as Element;
 use Zend\Form\Element\Submit;
-use Zend\Form\Form;
 use Zend\Form\View\Helper\FormElementErrors;
 use Zend\Form\View\Helper\FormLabel;
 use Zend\Form\View\Helper\FormRadio;
 use Zend\Form\View\Helper\FormSelect;
 use Zend\Form\View\Helper\FormSubmit;
-use Zend\I18n\Translator\TranslatorInterface;
 
 /** @var FormLabel $formLabel */
+/** @var FormRadio $formRadio */
+/** @var FormSelect $formSelect */
+/** @var FormSubmit $formSubmit */
+/** @var FormElementErrors $formElementErrors */
 $formLabel = $this->formLabel();
-/**@var FormRadio $formRadio */
 $formRadio = $this->formRadio();
-/**@var FormSelect $formSelect */
 $formSelect = $this->formSelect();
-/**@var FormSubmit $formSubmit */
 $formSubmit = $this->formSubmit();
-/** @var FormElementErrors $formElementErrors */
 $formElementErrors = $this->formElementErrors();
 $formLabel->setTranslatorTextDomain('fid');
 $formSelect->setTranslatorTextDomain('fid');
 $formRadio->setTranslatorTextDomain('fid');
 $formSubmit->setTranslatorTextDomain('fid');
 $formElementErrors->setTranslatorTextDomain('fid');
-/** @var TranslatorInterface $translator */
-$translator = $this->getHelperPluginManager()->get('translate')
-    ->getTranslator();
-
-$formLabel->setTranslator($translator);
-$formElementErrors->setTranslator($translator);
-
-/** @var Form $form */
-/** @var User $user */
-$user = $this->user;
-$userId = $user->getId();
-$form = $this->form;
-$form->setAttribute('method', 'post');
-$form->setAttribute('action', $this->url('fid/admin/edit',['userid' => $userId]));
-$form->setAttribute('class', 'form-horizontal');
-$form->prepare();
-
-$this->headTitle($this->translate('Profile Form'));
-$this->headTitle($this->translate("fid::user_update_form_title"));
+$this->headTitle($title = $this->translate("fid::user_edit_form_title", [
+    '%%userid%%'   => $user->getId(),
+    '%%username%%' => $user->getUsername()
+]));
+$editableFields = $this->config['Admin']['editable_user_fields'] ?? [];
+$form->setAttributes(['class' => 'row']);
+echo $this->form()->openTag($form);
 ?>
-<!-- fid: admin - edit -->
-    <h2><?= $this->translate("fid::user_edit_form_title",['%%userid%%' => $userId, '%%username%%' => $user->getUsername()]) ?></h2>
+
+<h2 class="row col-md-12"><?= $title ?></h2>
+<div class="row col-md-12"><?= $this->transEsc("fid::required_fields_note") ?></div>
 <?= $this->flashmessages() ?>
-<?= $this->form()->openTag($form) ?>
-<?php
-/** @var Element\Hidden $elemUserId */
-$elemUserId = $form->get('userId');
-$elemUserId->setValue($userId);
-?>
-    <div class="form-group"><?=$this->formHidden($elemUserId)?></div>
+<br/>
 
-<? /* home library */ ?>
-<?php
-/** @var Element\Select $elemHomeLibrary */
-$elemHomeLibrary = $form->get('homeLibrary');
-$elemHomeLibrary->setLabelAttributes(['class' => 'inline col-md-4 col-sm-10']);
-$elemHomeLibrary->setAttributes(['class' => 'form-control inline col-sm-6']);
-$elemHomeLibrary->setValue($user->getHomeLibrary());
-if (!in_array('HomeLibrary',$editableFields)) {
-    $elemHomeLibrary->setAttribute('readonly', '1');
-}
-?>
-    <div class="form-group">
-        <?= $this->formLabel($elemHomeLibrary) ?>
-        <?= $this->formSelect($elemHomeLibrary) ?>
-        <?= $this->formElementErrors($elemHomeLibrary) ?>
-    </div>
+<? /* id */ ?>
+<?= $this->formElement($form->get('id')) ?>
 
 <? /* salutation */ ?>
 <?php
 /** @var Element\Select $elemSalutation */
 $elemSalutation = $form->get('salutation');
-$elemSalutation->setLabelAttributes(['class' => 'inline col-md-4 col-sm-10']);
-$elemSalutation->setAttributes(['class' => 'form-control inline col-sm-2']);
-$elemSalutation->setValue($user->getSalutation());
-if (!in_array('Salutation',$editableFields)) {
+$elemSalutation->setLabelAttributes(['class' => 'col-md-3']);
+$elemSalutation->setAttributes(['class' => 'col-md-3']);
+if (!in_array('Salutation', $editableFields)) {
     $elemSalutation->setAttribute('readonly', '1');
 }
 ?>
-    <div class="form-group">
-        <?= $this->formLabel($elemSalutation) ?>
-        <?= $this->formSelect($elemSalutation) ?>
-
-    </div>
+<div class="row">
+    <?= $this->formLabel($elemSalutation) ?>
+    <?= $this->formSelect($elemSalutation) ?>
+</div>
 
 <? /* academic title */ ?>
 <?php
 /** @var Element\Text $elemAcademicTitle */
-$elemAcademicTitle = $form->get('academicTitle');
-$elemAcademicTitle->setLabelAttributes(['class' => 'inline col-md-4 col-sm-10']);
-$elemAcademicTitle->setAttributes(['class' => 'form-control']);
-$elemAcademicTitle->setValue($user->getAcademicTitle());
-if (!in_array('AcademicTitle',$editableFields)) {
+$elemAcademicTitle = $form->get('academic_title');
+$elemAcademicTitle->setLabelAttributes(['class' => 'col-md-3']);
+$elemAcademicTitle->setAttributes(['class' => 'col-md-3']);
+if (!in_array('AcademicTitle', $editableFields)) {
     $elemAcademicTitle->setAttribute('readonly', '1');
 }
 ?>
-    <div class="form-group">
-        <?= $this->formLabel($elemAcademicTitle) ?>
-        <?= $this->formElement($elemAcademicTitle) ?>
-    </div>
+<div class="row">
+    <?= $this->formLabel($elemAcademicTitle) ?>
+    <?= $this->formElement($elemAcademicTitle) ?>
+    <br/>
+</div>
 
 <? /* firstname */ ?>
 <?php
 /** @var Element\Text $elemFirstname */
 $elemFirstname = $form->get('firstname');
-$elemFirstname->setLabelAttributes(['class' => 'inline col-md-4 col-sm-10']);
-$elemFirstname->setAttributes(['class' => 'form-control']);
-$elemFirstname->setValue($user->getFirstname());
-if (!in_array('Firstname',$editableFields)) {
+$elemFirstname->setLabelAttributes(['class' => 'col-md-3']);
+$elemFirstname->setAttributes(['class' => 'col-md-3']);
+if (!in_array('Firstname', $editableFields)) {
     $elemFirstname->setAttribute('readonly', '1');
 }
 ?>
-    <div class="form-group">
-        <?= $this->formLabel($elemFirstname) ?>
-        <?= $this->formElement($elemFirstname) ?>
-        <?= $this->formElementErrors($elemFirstname) ?>
-    </div>
+<div class="row">
+    <?= $this->formLabel($elemFirstname) ?>
+    <?= $this->formElement($elemFirstname) ?>
+    <?= $this->formElementErrors($elemFirstname) ?>
+</div>
 
 <? /* lastname */ ?>
 <?php
 /** @var Element\Text $elemLastname */
 $elemLastname = $form->get('lastname');
-$elemLastname->setLabelAttributes(['class' => 'inline col-md-4 col-sm-10']);
-$elemLastname->setAttributes(['class' => 'form-control']);
-$elemLastname->setValue($user->getLastname());
-if (!in_array('Lastname',$editableFields)) {
+$elemLastname->setLabelAttributes(['class' => 'col-md-3']);
+$elemLastname->setAttributes(['class' => 'col-md-3']);
+if (!in_array('Lastname', $editableFields)) {
     $elemLastname->setAttribute('readonly', '1');
 }
 ?>
-    <div class="form-group">
-        <?= $this->formLabel($elemLastname) ?>
-        <?= $this->formElement($elemLastname) ?>
-        <?= $this->formElementErrors($elemLastname) ?>
-    </div>
-
-<? /* year of birth */ ?>
-<?php
-/** @var Element\Text $elemYearOfBirth */
-$elemYearOfBirth = $form->get('yearOfBirth');
-$elemYearOfBirth->setLabelAttributes(['class' => 'inline col-md-4 col-sm-10']);
-$elemYearOfBirth->setAttributes(['class' => 'form-control']);
-$elemYearOfBirth->setValue($user->getYearOfBirth());
-if (!in_array('YearOfBirth',$editableFields)) {
-    $elemYearOfBirth->setAttribute('readonly', '1');
-}
-?>
-    <div class="form-group">
-        <?= $this->formLabel($elemYearOfBirth) ?>
-        <?= $this->formElement($elemYearOfBirth) ?>
-        <?= $this->formElementErrors($elemYearOfBirth) ?>
-    </div>
+<div class="row">
+    <?= $this->formLabel($elemLastname) ?>
+    <?= $this->formElement($elemLastname) ?>
+    <?= $this->formElementErrors($elemLastname) ?>
+</div>
 
 <? /* college */ ?>
 <?php
 /** @var Element\Text $elemCollege */
 $elemCollege = $form->get('college');
-$elemCollege->setLabelAttributes(['class' => 'inline col-md-4 col-sm-10']);
-$elemCollege->setAttributes(['class' => 'form-control']);
-$elemCollege->setValue($user->getCollege());
-if (!in_array('College',$editableFields)) {
+$elemCollege->setLabelAttributes(['class' => 'col-md-3']);
+$elemCollege->setAttributes(['class' => 'col-md-3']);
+if (!in_array('College', $editableFields)) {
     $elemCollege->setAttribute('readonly', '1');
 }
 ?>
-    <div class="form-group">
-        <?= $this->formLabel($elemCollege) ?>
-        <?= $this->formElement($elemCollege) ?>
-        <?= $this->formElementErrors($elemCollege) ?>
-    </div>
+<div class="row">
+    <?= $this->formLabel($elemCollege) ?>
+    <?= $this->formElement($elemCollege) ?>
+    <?= $this->formElementErrors($elemCollege) ?>
+</div>
+
+<? /* home library */ ?>
+<?php
+/** @var Element\Select $elemHomeLibrary */
+$elemHomeLibrary = $form->get('home_library');
+$elemHomeLibrary->setLabelAttributes(['class' => 'col-md-3']);
+$elemHomeLibrary->setAttributes(['class' => 'col-md-6']);
+if (!in_array('HomeLibrary', $editableFields)) {
+    $elemHomeLibrary->setAttribute('disabled', '1');
+}
+?>
+<div class="row">
+    <?= $this->formLabel($elemHomeLibrary) ?>
+    <?= $this->formSelect($elemHomeLibrary) ?>
+    <?= $this->formElementErrors($elemHomeLibrary) ?>
+</div>
 
-<? /* job title */ ?>
+<? /* user group */ ?>
 <?php
-/** @var Element\Text $elemJobTitle */
-$elemJobTitle = $form->get('jobTitle');
-$elemJobTitle->setLabelAttributes(['class' => 'inline col-md-4 col-sm-10']);
-$elemJobTitle->setAttributes(['class' => 'form-control']);
-$elemJobTitle->setValue($user->getJobTitle());
-if (!in_array('JobTitle',$editableFields)) {
+/** @var Element\Radio $elemJobTitle */
+$elemJobTitle = $form->get('job_title');
+$elemJobTitle->setLabelAttributes(['class' => 'col-md-3']);
+$elemJobTitle->setAttributes(['class' => 'col-md-6']);
+if (!in_array('JobTitle', $editableFields)) {
     $elemJobTitle->setAttribute('readonly', '1');
 }
 ?>
-    <div class="form-group">
-        <?= $this->formLabel($elemJobTitle) ?>
-        <?= $this->formElement($elemJobTitle) ?>
-        <?= $this->formElementErrors($elemJobTitle) ?>
-    </div>
+<div class="row">
+    <?= $this->formLabel($elemJobTitle) ?>
+    <?= $this->formElement($elemJobTitle) ?>
+    <?= $this->formElementErrors($elemJobTitle) ?>
+</div>
 
 <? /* Permissions */ ?>
 <?php
-/** @var Element\MultiCheckbox $elemPermissions */
+/** @var Element\Collection $elemPermissions */
+/** @var Element\Select[] $elemPermissionsElems */
 $elemPermissions = $form->get('permissions');
-$elemPermissions->setLabelAttributes(['class' => 'inline col-md-4 col-sm-10']);
-if (!in_array('Permissions',$editableFields)) {
-    $elemPermissions->setAttribute('readonly', '1');
+$elemPermissions->setLabelAttributes(['class' => 'col-md-3']);
+$elemPermissionsElems = $elemPermissions->getElements();
+$permissions = $this->config['Admin']['permission_options'] ?? [];
+foreach ($permissions as $permission) {
+    $element = $elemPermissionsElems[$permission];
+    $element->setLabel("permission_$permission");
+    $element->setAttributes(['class' => 'col-md-2']);
+    $element->setLabelAttributes(['class' => 'col-md-6']);
+    $element->setAttribute('id', $element->getName());
+    $elements[] = $element;
 }
 ?>
-    <div class="form-group">
-        <?= $this->formLabel($elemPermissions) ?>
-        <div class="permission-options col-sm-7">
-            <?= $this->formMultiCheckbox($elemPermissions) ?>
+
+<div class="row">
+    <?= $this->formLabel($elemPermissions) ?>
+    <div class="col-md-9">
+        <?php foreach ($elements as $element): ?>
+        <div class="row">
+            <?= $this->formElement($element) ?>
+            <?= $this->formLabel($element) ?>
+        </div>
+        <? endforeach; ?>
+        <div class="row">
+            <?= $this->formElementErrors($elemPermissions) ?>
         </div>
-        <?= $this->formElementErrors($elemPermissions) ?>
     </div>
+</div>
+
 
 <? /* submit button */ ?>
 <?php
@@ -235,15 +211,15 @@ if (!in_array('Permissions',$editableFields)) {
 $elemSubmit = $form->get('submit');
 $elemSubmit->setAttributes(['class' => 'btn btn-primary']);
 ?>
-    <div class="form-group">
-        <div class="col-lg-11 col-md-9 col-sm-11 col-xs-12">
-            <?= $this->formSubmit($elemSubmit) ?>
-            <a href="<?= $this->url('fid/admin/list') ?>"
-               class="btn btn-primary">
-                <?= $this->transEsc('Cancel') ?>
-            </a>
-        </div>
+<div class="row">
+    <div class="col-lg-11 col-md-9 col-sm-11 col-xs-12">
+        <?= $this->formSubmit($elemSubmit) ?>
+        <a href="<?= $this->url('fid/admin/list') ?>"
+           class="btn btn-primary">
+            <?= $this->transEsc('Cancel') ?>
+        </a>
     </div>
+</div>
 
 <?= $this->form()->closeTag($form) ?>
 <!-- fid: admin - edit - END -->
\ No newline at end of file
diff --git a/themes/fid/templates/fid/admin/list-entry.phtml b/themes/fid/templates/fid/admin/list-entry.phtml
index 758790b43d39c1df1c9ad2ff3ee9d62db0b45931..54c1aef9c4ee9b185cdc7c0b84c87fbc2c88c2cf 100644
--- a/themes/fid/templates/fid/admin/list-entry.phtml
+++ b/themes/fid/templates/fid/admin/list-entry.phtml
@@ -1,11 +1,11 @@
 <!-- fid: user - admin - list-entry -->
 <?php
 $permissions  = [];
-if (!empty($permissions = $user->getPermissions())) {
-    foreach ($permissions as $key => &$perm) {
-        $perm = $this->escapeHtml($key).' ('.$this->escapeHtml($perm).')';
-    }
+foreach ($config['Admin']['permission_options'] ?? [] as $perm) {
+    $state = $user->getPermissions()[$perm];
+    $permissions[$perm] = $this->escapeHtml($perm).' ('.$this->escapeHtml($state).')';
 }
+
 foreach ($this->fields as $field):
 ?>
 <?php if ($field === 'Permissions'): ?>
diff --git a/themes/fid/templates/fid/admin/list.phtml b/themes/fid/templates/fid/admin/list.phtml
index a5c81b74f18d84ec99feefed4fec3d6b9dbd1965..3d0c9fefd4a38cab6481f753689144e0074ce41b 100644
--- a/themes/fid/templates/fid/admin/list.phtml
+++ b/themes/fid/templates/fid/admin/list.phtml
@@ -12,7 +12,7 @@
     </tr>
     <?php foreach ($list as $id => $user):?>
         <?php $tooltip = $this->translate('fid::user_edit',['%%userid%%' => $id]); ?>
-        <tr><td><a href="<?=$this->url('fid/admin/edit',['userid' => $id])?>" title="<?=$tooltip?>"><i class="fa fa-pencil-square-o"></i><span class="sr-only"><?=$tooltip?></span></a></td><th><?=$id?></th><?= $this->render('fid/admin/list-entry',['user' => $user,'fields'=>$fields]) ?></tr>
+        <tr><td><a href="<?=$this->url('fid/admin/edit',['userid' => $id])?>" title="<?=$tooltip?>"><i class="fa fa-pencil-square-o"></i><span class="sr-only"><?=$tooltip?></span></a></td><th><?=$id?></th><?= $this->render('fid/admin/list-entry',['user' => $user,'fields'=>$fields, 'config' => $config]) ?></tr>
     <?php endforeach; ?>
     </table>
 <?php else: ?>
diff --git a/themes/fid/templates/fid/user/update-addresses.phtml b/themes/fid/templates/fid/user/address-collection.phtml
similarity index 54%
rename from themes/fid/templates/fid/user/update-addresses.phtml
rename to themes/fid/templates/fid/user/address-collection.phtml
index 90142130e64d6d8b950a48a4948dd6ace45268d0..8b2e620bcb47ec7b6596af326d7a16446aa951ad 100644
--- a/themes/fid/templates/fid/user/update-addresses.phtml
+++ b/themes/fid/templates/fid/user/address-collection.phtml
@@ -19,25 +19,14 @@
  * @license  http://opensource.org/licenses/gpl-2.0.php GNU GPLv2
  */
 
-use fid\Service\DataTransferObject\Address;
-use fid\Service\DataTransferObject\User;
-use Zend\Form\Element\Collection;
+use Zend\Form\Fieldset;
 use Zend\Form\Form;
 
 /** @var Form $form */
-/** @var User $user */
-/** @var Collection $collection */
-list($user, $form) = [$this->user, $this->form];
-$collection = $form->get('addresses');
-$addresses = $user->getAddresses() ?: [new Address()];
-$collection->setCount($count = count($addresses));
-if (count($collection->getFieldsets()) < $count) {
-  $collection->prepareElement($form);
-}
-$context = compact('form', 'user', 'collection', 'addresses');
-foreach ($collection->getFieldsets() as $index => $fieldset) {
-  $address = $addresses[$index];
-  $context = compact('index', 'address', 'fieldset') + $context;
-  echo $this->render('update-address.phtml', $context);
+/** @var Fieldset $address */
+$form = $this->form;
+foreach ($form->get('addresses')->getFieldsets() as $address) {
+    $context = compact('form', 'address');
+    echo $this->render($address->getOption('template'), $context);
 }
 ?>
diff --git a/themes/fid/templates/fid/user/update-address.phtml b/themes/fid/templates/fid/user/address-fieldset.phtml
similarity index 59%
rename from themes/fid/templates/fid/user/update-address.phtml
rename to themes/fid/templates/fid/user/address-fieldset.phtml
index 54aac2961f2177d022e055258441d7abfb884cd5..c26c1973cd3a033b54fcd5d552dec601d94e68ee 100644
--- a/themes/fid/templates/fid/user/update-address.phtml
+++ b/themes/fid/templates/fid/user/address-fieldset.phtml
@@ -23,89 +23,81 @@ use fid\Service\DataTransferObject\Address;
 use Zend\Form\Fieldset;
 use Zend\Form\Element;
 
-/** @var Address $address */
-/** @var Fieldset $fieldset */
+/** @var Fieldset $address */
 $address = $this->address;
-$fieldset = $this->fieldset;
 ?>
 
+<h3><?= $this->translate('fid::' . $address->getLabel()) ?></h3>
+
 <? /* id */ ?>
 <?php
-
-if ($id = $address->getId()) {
-  /** @var Element\Hidden $elemId */
-  $elemId = $fieldset->get('id');
-  $elemId->setValue($address->getId());
-  echo $this->formElement($elemId);
+$elemId = $address->get('id');
+if ($elemId->getValue()) {
+    echo $this->formElement($elemId);
 }
 ?>
 
 <? /* first line */ ?>
 <?php
 /** @var Element\Text $elemLine1 */
-$elemLine1 = $fieldset->get('line1');
-$elemLine1->setValue($elemLine1->getValue() ?? $address->getLine1());
+$elemLine1 = $address->get('line1');
 $elemLine1->setLabelAttributes(['class' => 'col-md-4']);
 $elemLine1->setAttributes(['class' => 'form-control']);
 ?>
 <div class="form-group">
-  <?= $this->formLabel($elemLine1) ?>
-  <?= $this->formElement($elemLine1) ?>
-  <?= $this->formElementErrors($elemLine1) ?>
+    <?= $this->formLabel($elemLine1) ?>
+    <?= $this->formElement($elemLine1) ?>
+    <?= $this->formElementErrors($elemLine1) ?>
 </div>
 
 <? /* second line */ ?>
 <?php
 /** @var Element\Text $elemLine2 */
-$elemLine2 = $fieldset->get('line2');
-$elemLine2->setValue($elemLine2->getValue() ?? $address->getLine2());
+$elemLine2 = $address->get('line2');
 $elemLine2->setLabelAttributes(['class' => 'col-md-4']);
 $elemLine2->setAttributes(['class' => 'form-control']);
 ?>
 <div class="form-group">
-  <?= $this->formLabel($elemLine2) ?>
-  <?= $this->formElement($elemLine2) ?>
-  <?= $this->formElementErrors($elemLine2) ?>
+    <?= $this->formLabel($elemLine2) ?>
+    <?= $this->formElement($elemLine2) ?>
+    <?= $this->formElementErrors($elemLine2) ?>
 </div>
 
 <? /* address zip */ ?>
 <?php
 /** @var Element\Text $elemZip */
-$elemZip = $fieldset->get('zip');
-$elemZip->setValue($elemZip->getValue() ?? $address->getZip());
+$elemZip = $address->get('zip');
 $elemZip->setLabelAttributes(['class' => 'col-md-4']);
 $elemZip->setAttributes(['class' => 'form-control']);
 ?>
 <div class="form-group">
-  <?= $this->formLabel($elemZip) ?>
-  <?= $this->formElement($elemZip) ?>
-  <?= $this->formElementErrors($elemZip) ?>
+    <?= $this->formLabel($elemZip) ?>
+    <?= $this->formElement($elemZip) ?>
+    <?= $this->formElementErrors($elemZip) ?>
 </div>
 
 <? /* city */ ?>
 <?php
 /** @var Element\Text $elemCity */
-$elemCity = $fieldset->get('city');
-$elemCity->setValue($elemCity->getValue() ?? $address->getCity());
+$elemCity = $address->get('city');
 $elemCity->setLabelAttributes(['class' => 'col-md-4']);
 $elemCity->setAttributes(['class' => 'form-control']);
 ?>
 <div class="form-group">
-  <?= $this->formLabel($elemCity) ?>
-  <?= $this->formElement($elemCity) ?>
-  <?= $this->formElementErrors($elemCity) ?>
+    <?= $this->formLabel($elemCity) ?>
+    <?= $this->formElement($elemCity) ?>
+    <?= $this->formElementErrors($elemCity) ?>
 </div>
 
 <? /* country */ ?>
 <?php
 /** @var Element\Text $elemCountry */
-$elemCountry = $fieldset->get('country');
-$elemCountry->setValue($elemCountry->getValue() ?? $address->getCountry());
+$elemCountry = $address->get('country');
 $elemCountry->setLabelAttributes(['class' => 'col-md-4']);
 $elemCountry->setAttributes(['class' => 'form-control']);
 ?>
 <div class="form-group">
-  <?= $this->formLabel($elemCountry) ?>
-  <?= $this->formElement($elemCountry) ?>
-  <?= $this->formElementErrors($elemCountry) ?>
+    <?= $this->formLabel($elemCountry) ?>
+    <?= $this->formElement($elemCountry) ?>
+    <?= $this->formElementErrors($elemCountry) ?>
 </div>
diff --git a/themes/fid/templates/fid/user/create.phtml b/themes/fid/templates/fid/user/create.phtml
index 7a2bf2e0360b3ca5615af9954f400c8c2a05e9eb..d192ffb938178ed86dbe1feccfab4dcb21609d7f 100644
--- a/themes/fid/templates/fid/user/create.phtml
+++ b/themes/fid/templates/fid/user/create.phtml
@@ -20,56 +20,42 @@
  * @license  http://opensource.org/licenses/gpl-2.0.php GNU GPLv2
  */
 
+use Zend\Form\Element;
 use Zend\Form\Element\Checkbox;
 use Zend\Form\Element\Submit;
 use Zend\Form\Form;
-use Zend\Form\Element as Element;
 use Zend\Form\View\Helper\FormElementErrors;
 use Zend\Form\View\Helper\FormLabel;
 use Zend\Form\View\Helper\FormRadio;
 use Zend\Form\View\Helper\FormSelect;
 use Zend\Form\View\Helper\FormSubmit;
-use Zend\I18n\Translator\TranslatorInterface;
 
+/** @var Form $form */
 /** @var FormLabel $formLabel */
+/** @var FormRadio $formRadio */
+/** @var FormSelect $formSelect */
+/** @var FormSubmit $formSubmit */
+/** @var FormElementErrors $formElementErrors */
+$form = $this->form;
 $formLabel = $this->formLabel();
-/**@var FormRadio $formRadio */
 $formRadio = $this->formRadio();
-/**@var FormSelect $formSelect */
 $formSelect = $this->formSelect();
-/**@var FormSubmit $formSubmit */
 $formSubmit = $this->formSubmit();
-/** @var FormElementErrors $formElementErrors */
 $formElementErrors = $this->formElementErrors();
 $formLabel->setTranslatorTextDomain('fid');
 $formSelect->setTranslatorTextDomain('fid');
 $formRadio->setTranslatorTextDomain('fid');
 $formSubmit->setTranslatorTextDomain('fid');
 $formElementErrors->setTranslatorTextDomain('fid');
-/** @var TranslatorInterface $translator */
-$translator = $this->getHelperPluginManager()->get('translate')
-    ->getTranslator();
-
-$formLabel->setTranslator($translator);
-$formElementErrors->setTranslator($translator);
-
-/** @var Form $form */
-$form = $this->form;
-$form->setAttribute('method', 'post');
-$form->setAttribute('action', $this->url('fid/user/create'));
-$form->setAttribute('class', 'fid-user-create-form registration');
-$form->prepare();
-
-$this->headTitle($this->translate('Profile Form'));
-$this->headTitle($this->translate("fid::user_create_form_title"));
+$this->headTitle($title = $this->translate("fid::user_create_form_title"));
 ?>
 
+<h2><?= $title ?></h2>
+<div><?= $this->transEsc("fid::required_fields_note") ?></div>
 <?= $this->flashmessages() ?>
 <?= $this->form()->openTag($form) ?>
-    <h2><?= $this->translate("fid::user_create_form_title") ?></h2>
-    <div class="subito-pg">
-        * <?= $this->transEsc("This field is required") ?>
-    </div>
+<br/>
+
 <? /* username */ ?>
 <?php
 /** @var Element\Text $elemUsername */
@@ -77,16 +63,16 @@ $elemUsername = $form->get('username');
 $elemUsername->setLabelAttributes(['class' => 'col-md-4']);
 $elemUsername->setAttributes(['class' => 'form-control', 'disabled' => 1]);
 ?>
-    <div class="form-group">
-        <?= $this->formLabel($elemUsername) ?>
-        <?= $this->formElement($elemUsername) ?>
-        <?= $this->formElementErrors($elemUsername) ?>
-        <?php
-        $elemUsername->removeAttribute('disabled');
-        $elemUsername->setAttribute('type', 'hidden');
-        echo $this->formElement($elemUsername);
-        ?>
-    </div>
+<div class="form-group">
+    <?= $this->formLabel($elemUsername) ?>
+    <?= $this->formElement($elemUsername) ?>
+    <?= $this->formElementErrors($elemUsername) ?>
+    <?php
+    $elemUsername->removeAttribute('disabled');
+    $elemUsername->setAttribute('type', 'hidden');
+    ?>
+    <?= $this->formElement($elemUsername) ?>
+</div>
 
 <? /* password */ ?>
 <?php
@@ -95,37 +81,24 @@ $elemPassword = $form->get('password');
 $elemPassword->setLabelAttributes(['class' => 'col-md-4']);
 $elemPassword->setAttributes(['class' => 'form-control']);
 ?>
-    <div class="form-group">
-        <?= $this->formLabel($elemPassword) ?>
-        <?= $this->formElement($elemPassword) ?>
-        <?= $this->formElementErrors($elemPassword) ?>
-    </div>
+<div class="form-group">
+    <?= $this->formLabel($elemPassword) ?>
+    <?= $this->formElement($elemPassword) ?>
+    <?= $this->formElementErrors($elemPassword) ?>
+</div>
 
 <? /* password confirmation */ ?>
 <?php
 /** @var Element\Password $elemPasswordConfirmation */
-$elemPasswordConfirmation = $form->get('passwordConfirmation');
+$elemPasswordConfirmation = $form->get('password_confirmation');
 $elemPasswordConfirmation->setLabelAttributes(['class' => 'col-md-4']);
 $elemPasswordConfirmation->setAttributes(['class' => 'form-control']);
 ?>
-    <div class="form-group">
-        <?= $this->formLabel($elemPasswordConfirmation) ?>
-        <?= $this->formElement($elemPasswordConfirmation) ?>
-        <?= $this->formElementErrors($elemPasswordConfirmation) ?>
-    </div>
-
-<? /* home library */ ?>
-<?php
-/** @var Element\Select $elemHomeLibrary */
-$elemHomeLibrary = $form->get('homeLibrary');
-$elemHomeLibrary->setLabelAttributes(['class' => 'col-md-4']);
-$elemHomeLibrary->setAttributes(['class' => 'form-control']);
-?>
-    <div class="form-group">
-        <?= $this->formLabel($elemHomeLibrary) ?>
-        <?= $this->formSelect($elemHomeLibrary) ?>
-        <?= $this->formElementErrors($elemHomeLibrary) ?>
-    </div>
+<div class="form-group">
+    <?= $this->formLabel($elemPasswordConfirmation) ?>
+    <?= $this->formElement($elemPasswordConfirmation) ?>
+    <?= $this->formElementErrors($elemPasswordConfirmation) ?>
+</div>
 
 <? /* salutation */ ?>
 <?php
@@ -134,22 +107,22 @@ $elemSalutation = $form->get('salutation');
 $elemSalutation->setLabelAttributes(['class' => 'col-md-4']);
 $elemSalutation->setAttributes(['class' => 'form-control']);
 ?>
-    <div class="form-group">
-        <?= $this->formLabel($elemSalutation) ?>
-        <?= $this->formSelect($elemSalutation) ?>
-    </div>
+<div class="form-group">
+    <?= $this->formLabel($elemSalutation) ?>
+    <?= $this->formSelect($elemSalutation) ?>
+</div>
 
 <? /* academic title */ ?>
 <?php
 /** @var Element\Text $elemAcademicTitle */
-$elemAcademicTitle = $form->get('academicTitle');
+$elemAcademicTitle = $form->get('academic_title');
 $elemAcademicTitle->setLabelAttributes(['class' => 'col-md-4']);
 $elemAcademicTitle->setAttributes(['class' => 'form-control']);
 ?>
-    <div class="form-group">
-        <?= $this->formLabel($elemAcademicTitle) ?>
-        <?= $this->formElement($elemAcademicTitle) ?>
-    </div>
+<div class="form-group">
+    <?= $this->formLabel($elemAcademicTitle) ?>
+    <?= $this->formElement($elemAcademicTitle) ?>
+</div>
 
 <? /* firstname */ ?>
 <?php
@@ -158,11 +131,11 @@ $elemFirstname = $form->get('firstname');
 $elemFirstname->setLabelAttributes(['class' => 'col-md-4']);
 $elemFirstname->setAttributes(['class' => 'form-control']);
 ?>
-    <div class="form-group">
-        <?= $this->formLabel($elemFirstname) ?>
-        <?= $this->formElement($elemFirstname) ?>
-        <?= $this->formElementErrors($elemFirstname) ?>
-    </div>
+<div class="form-group">
+    <?= $this->formLabel($elemFirstname) ?>
+    <?= $this->formElement($elemFirstname) ?>
+    <?= $this->formElementErrors($elemFirstname) ?>
+</div>
 
 <? /* lastname */ ?>
 <?php
@@ -170,151 +143,79 @@ $elemFirstname->setAttributes(['class' => 'form-control']);
 $elemLastname = $form->get('lastname');
 $elemLastname->setLabelAttributes(['class' => 'col-md-4']);
 $elemLastname->setAttributes(['class' => 'form-control']);
-?>
-    <div class="form-group">
-        <?= $this->formLabel($elemLastname) ?>
-        <?= $this->formElement($elemLastname) ?>
-        <?= $this->formElementErrors($elemLastname) ?>
-    </div>
-
-<? /* year of birth */ ?>
-<?php
-/** @var Element\Text $elemYearOfBirth */
-$elemYearOfBirth = $form->get('yearOfBirth');
-$elemYearOfBirth->setLabelAttributes(['class' => 'col-md-4']);
-$elemYearOfBirth->setAttributes(['class' => 'form-control']);
-?>
-    <div class="form-group">
-        <?= $this->formLabel($elemYearOfBirth) ?>
-        <?= $this->formElement($elemYearOfBirth) ?>
-        <?= $this->formElementErrors($elemYearOfBirth) ?>
-    </div>
-
-<? /* college */ ?>
-<?php
-/** @var Element\Text $elemCollege */
-$elemCollege = $form->get('college');
-$elemCollege->setLabelAttributes(['class' => 'col-md-4']);
-$elemCollege->setAttributes(['class' => 'form-control']);
-?>
-    <div class="form-group">
-        <?= $this->formLabel($elemCollege) ?>
-        <?= $this->formElement($elemCollege) ?>
-        <?= $this->formElementErrors($elemCollege) ?>
-    </div>
-
-<? /* job title */ ?>
-<?php
-/** @var Element\Text $elemJobTitle */
-$elemJobTitle = $form->get('jobTitle');
-$elemJobTitle->setLabelAttributes(['class' => 'col-md-4']);
-$elemJobTitle->setAttributes(['class' => 'form-control']);
-?>
-    <div class="form-group">
-        <?= $this->formLabel($elemJobTitle) ?>
-        <?= $this->formElement($elemJobTitle) ?>
-        <?= $this->formElementErrors($elemJobTitle) ?>
-    </div>
-
-<? /* role (user group)  */ ?>
-<?php
-/** @var Element\Radio $accessLevel */
-$accessLevel = $form->get('accessLevel');
-?>
-    <div class="form-group">
-        <div class="col-md-4">
-            <?= $this->formLabel($accessLevel) ?>
-        </div>
-        <div class="col-md-8">
-            <?= $this->formRadio($accessLevel) ?>
-        </div>
-        <?= $this->formElementErrors($accessLevel) ?>
-    </div>
-
-<?php
-/** @var Element\Text $elemAddressLine1 */
-$elemAddressLine1 = $form->get('addressLine1');
-$elemAddressLine1->setLabelAttributes(['class' => 'col-md-4']);
-$elemAddressLine1->setAttributes(['class' => 'form-control']);
 ?>
 <div class="form-group">
-  <?= $this->formLabel($elemAddressLine1) ?>
-  <?= $this->formElement($elemAddressLine1) ?>
-  <?= $this->formElementErrors($elemAddressLine1) ?>
+    <?= $this->formLabel($elemLastname) ?>
+    <?= $this->formElement($elemLastname) ?>
+    <?= $this->formElementErrors($elemLastname) ?>
 </div>
 
-<? /* second address line */ ?>
+<? /* home library */ ?>
 <?php
-/** @var Element\Text $elemAddressLine2 */
-$elemAddressLine2 = $form->get('addressLine2');
-$elemAddressLine2->setLabelAttributes(['class' => 'col-md-4']);
-$elemAddressLine2->setAttributes(['class' => 'form-control']);
+/** @var Element\Select $elemHomeLibrary */
+$elemHomeLibrary = $form->get('home_library');
+$elemHomeLibrary->setLabelAttributes(['class' => 'col-md-4']);
+$elemHomeLibrary->setAttributes(['class' => 'form-control']);
 ?>
 <div class="form-group">
-  <?= $this->formLabel($elemAddressLine2) ?>
-  <?= $this->formElement($elemAddressLine2) ?>
-  <?= $this->formElementErrors($elemAddressLine2) ?>
+    <?= $this->formLabel($elemHomeLibrary) ?>
+    <?= $this->formSelect($elemHomeLibrary) ?>
+    <?= $this->formElementErrors($elemHomeLibrary) ?>
 </div>
 
-<? /* address zip */ ?>
+<? /* user group */ ?>
 <?php
-/** @var Element\Text $elemAddressZip */
-$elemAddressZip = $form->get('addressZip');
-$elemAddressZip->setLabelAttributes(['class' => 'col-md-4']);
-$elemAddressZip->setAttributes(['class' => 'form-control']);
+/** @var Element\Radio $elemJobTitle */
+$elemJobTitle = $form->get('job_title');
 ?>
 <div class="form-group">
-  <?= $this->formLabel($elemAddressZip) ?>
-  <?= $this->formElement($elemAddressZip) ?>
-  <?= $this->formElementErrors($elemAddressZip) ?>
+    <div class="col-md-4">
+        <?= $this->formLabel($elemJobTitle) ?>
+    </div>
+    <div class="col-md-8">
+        <?= $this->formRadio($elemJobTitle) ?>
+    </div>
+    <?= $this->formElementErrors($elemJobTitle) ?>
 </div>
 
-<? /* address city */ ?>
+<? /* college */ ?>
 <?php
-/** @var Element\Text $elemAddressCity */
-$elemAddressCity = $form->get('addressCity');
-$elemAddressCity->setLabelAttributes(['class' => 'col-md-4']);
-$elemAddressCity->setAttributes(['class' => 'form-control']);
+/** @var Element\Text $elemCollege */
+$elemCollege = $form->get('college');
+$elemCollege->setLabelAttributes(['class' => 'col-md-4']);
+$elemCollege->setAttributes(['class' => 'form-control']);
 ?>
 <div class="form-group">
-  <?= $this->formLabel($elemAddressCity) ?>
-  <?= $this->formElement($elemAddressCity) ?>
-  <?= $this->formElementErrors($elemAddressCity) ?>
+    <?= $this->formLabel($elemCollege) ?>
+    <?= $this->formElement($elemCollege) ?>
+    <?= $this->formElementErrors($elemCollege) ?>
 </div>
 
-<? /* address country */ ?>
-<?php
-/** @var Element\Text $elemAddressCountry */
-$elemAddressCountry = $form->get('addressCountry');
-$elemAddressCountry->setLabelAttributes(['class' => 'col-md-4']);
-$elemAddressCountry->setAttributes(['class' => 'form-control']);
-?>
-<div class="form-group">
-  <?= $this->formLabel($elemAddressCountry) ?>
-  <?= $this->formElement($elemAddressCountry) ?>
-  <?= $this->formElementErrors($elemAddressCountry) ?>
-</div>
+<? /* addresses */ ?>
+<?= $this->render('address-collection.phtml') ?>
 
 <? /* eula privacy policy */ ?>
 <?php
 /** @var Checkbox $elemEulaAccepted */
-$elemEulaAccepted = $form->get('eulaAccepted');
-$elemEulaAccepted->setAttribute('id', 'eulaAccepted');
-?>
-    <div class="form-group eula">
-        <div>
-            <?= $this->formElement($elemEulaAccepted) ?>
-            <?= $this->formLabel()->openTag($elemEulaAccepted) ?>
-            <?= $this->translate("fid::policy_text") ?>
-            <?php $url = $this->url('fid/user/policy') ?>
-            <a data-lightbox href="<?= $url ?>"><?= $this->translate("fid::policy") ?></a>
-            <?= $this->translate("fid::terms_text") ?>
-            <?php $url = $this->url('fid/user/terms') ?>
-            <a data-lightbox href="<?= $url ?>"><?= $this->translate("fid::terms") ?></a>.
-            <?= $this->formLabel()->closeTag($elemEulaAccepted) ?>
-        </div>
-        <?= $this->formElementErrors($elemEulaAccepted) ?>
+$elemEulaAccepted = $form->get('eula_accepted');
+$elemEulaAccepted->setAttribute('id', 'eula-accepted');
+?>
+<div class="form-group eula">
+    <div>
+        <?= $this->formElement($elemEulaAccepted) ?>
+        <?= $this->formLabel()->openTag($elemEulaAccepted) ?>
+        <?= $this->translate("fid::policy_text") ?>
+        <?php $url = $this->url('fid/user/policy') ?>
+        <a data-lightbox
+           href="<?= $url ?>"><?= $this->translate("fid::policy") ?></a>
+        <?= $this->translate("fid::terms_text") ?>
+        <?php $url = $this->url('fid/user/terms') ?>
+        <a data-lightbox
+           href="<?= $url ?>"><?= $this->translate("fid::terms") ?></a>.
+        <?= $this->formLabel()->closeTag($elemEulaAccepted) ?>
     </div>
+    <?= $this->formElementErrors($elemEulaAccepted) ?>
+</div>
 
 <? /* submit button */ ?>
 <?php
@@ -322,10 +223,6 @@ $elemEulaAccepted->setAttribute('id', 'eulaAccepted');
 $elemSubmit = $form->get('submit');
 $elemSubmit->setAttributes(['class' => 'btn btn-primary']);
 ?>
-    <div class="form-group">
-        <div class="">
-            <?= $this->formSubmit($elemSubmit) ?>
-        </div>
-    </div>
 
+<div class="form-group"><?= $this->formSubmit($elemSubmit) ?></div>
 <?= $this->form()->closeTag($form) ?>
diff --git a/themes/fid/templates/fid/user/init.phtml b/themes/fid/templates/fid/user/init.phtml
index f444dca47ce27bd1eb09e35b7a76c55fc7cddc11..059c44c0effbe2016cbe9ce6e0b46723560d4939 100644
--- a/themes/fid/templates/fid/user/init.phtml
+++ b/themes/fid/templates/fid/user/init.phtml
@@ -25,43 +25,27 @@ use Zend\Form\Form;
 use Zend\Form\View\Helper\FormElementErrors;
 use Zend\Form\View\Helper\FormLabel;
 use Zend\Form\View\Helper\FormSubmit;
-use Zend\I18n\Translator\TranslatorInterface;
 
+/** @var Form $form */
 /** @var FormLabel $formLabel */
-$formLabel = $this->formLabel();
-/**@var FormSubmit $formSubmit */
-$formSubmit = $this->formSubmit();
+/** @var FormSubmit $formSubmit */
 /** @var FormElementErrors $formElementErrors */
-$formElementErrors = $this->formElementErrors();
-
+$form = $this->form;
+$formLabel = $this->formLabel();
 $formLabel->setTranslatorTextDomain('fid');
+$formSubmit = $this->formSubmit();
 $formSubmit->setTranslatorTextDomain('fid');
+$formElementErrors = $this->formElementErrors();
 $formElementErrors->setTranslatorTextDomain('fid');
-/** @var TranslatorInterface $translator */
-$translator = $this->getHelperPluginManager()->get('translate')
-    ->getTranslator();
-$formLabel->setTranslator($translator);
-$formElementErrors->setTranslator($translator);
-
-/** @var Form $form */
-$form = $this->form;
-$form->setAttribute('method', 'post');
-$form->setAttribute('action', $this->url('fid/user/init'));
-$form->setAttribute('class', 'fid-user-init-form registration');
-$form->prepare();
-
-$this->headTitle($this->translate("fid::user_init_form_title"));
+$this->headTitle($title = $this->translate("fid::user_init_form_title"));
 ?>
 
-<h2><?= $this->translate("fid::user_init_form_title") ?></h2>
-
-<div class="subito-pg">
-    * <?=$this->transEsc("This field is required")?>
-</div>
-
+<h2><?= $title ?></h2>
+<div><?= $this->transEsc("fid::required_fields_note") ?></div>
 <?= $this->flashmessages() ?>
 <?= $this->form()->openTag($form) ?>
 <br/>
+
 <? /* username */ ?>
 <?php
 /** @var Element\Text $elemUsername */
@@ -78,7 +62,7 @@ $elemUsername->setAttributes(['class' => 'form-control']);
 <? /* username confirmation */ ?>
 <?php
 /** @var Element\Text $elemUsernameConfirmation */
-$elemUsernameConfirmation = $form->get('usernameConfirmation');
+$elemUsernameConfirmation = $form->get('username_confirmation');
 $elemUsernameConfirmation->setLabelAttributes(['class' => 'control-label']);
 $elemUsernameConfirmation->setAttributes(['class' => 'form-control']);
 ?>
@@ -117,8 +101,8 @@ $elemLastname->setAttributes(['class' => 'form-control']);
 <? /* eula privacy policy */ ?>
 <?php
 /** @var Element\Checkbox $elemEulaAccepted */
-$elemEulaAccepted = $form->get('eulaAccepted');
-$elemEulaAccepted->setAttribute('id', $elemEulaAccepted->getAttribute('name') ?? 'eulaAccepted');
+$elemEulaAccepted = $form->get('eula_accepted');
+$elemEulaAccepted->setAttribute('id', 'eula-accepted');
 ?>
 <div class="form-group">
     <?= $this->formElement($elemEulaAccepted) ?>
@@ -142,9 +126,10 @@ $elemSubmit = $form->get('submit');
 $elemSubmit->setAttributes(['class' => 'btn btn-primary']);
 ?>
 <div class="form-group">
-    <a class="back-to-login btn btn-link" href="<?=$this->url('myresearch-userlogin') ?>">
+    <a class="back-to-login btn btn-link"
+       href="<?= $this->url('myresearch-userlogin') ?>">
         <i class="fa fa-chevron-left" aria-hidden="true"></i>
-        <?=$this->transEsc('Back')?>
+        <?= $this->transEsc('Back') ?>
     </a>
     <?= $this->formElement($elemSubmit) ?>
 </div>
diff --git a/themes/fid/templates/fid/user/update.phtml b/themes/fid/templates/fid/user/update.phtml
index 80338ec90c2c1913f9f1e6fadb3db464bcf6c4ae..1152a947b4631977aaa64b26460eb1f5cc5d8050 100644
--- a/themes/fid/templates/fid/user/update.phtml
+++ b/themes/fid/templates/fid/user/update.phtml
@@ -20,9 +20,7 @@
  * @license  http://opensource.org/licenses/gpl-2.0.php GNU GPLv2
  */
 
-use fid\Service\DataTransferObject\Address;
-use fid\Service\DataTransferObject\User;
-use Zend\Form\Element as Element;
+use Zend\Form\Element;
 use Zend\Form\Element\Submit;
 use Zend\Form\Form;
 use Zend\Form\View\Helper\FormElementErrors;
@@ -30,161 +28,114 @@ use Zend\Form\View\Helper\FormLabel;
 use Zend\Form\View\Helper\FormRadio;
 use Zend\Form\View\Helper\FormSelect;
 use Zend\Form\View\Helper\FormSubmit;
-use Zend\I18n\Translator\TranslatorInterface;
 
+/** @var Form $form */
 /** @var FormLabel $formLabel */
+/** @var FormRadio $formRadio */
+/** @var FormSelect $formSelect */
+/** @var FormSubmit $formSubmit */
+/** @var FormElementErrors $formElementErrors */
+$form = $this->form;
 $formLabel = $this->formLabel();
-/**@var FormRadio $formRadio */
 $formRadio = $this->formRadio();
-/**@var FormSelect $formSelect */
 $formSelect = $this->formSelect();
-/**@var FormSubmit $formSubmit */
 $formSubmit = $this->formSubmit();
-/** @var FormElementErrors $formElementErrors */
 $formElementErrors = $this->formElementErrors();
 $formLabel->setTranslatorTextDomain('fid');
 $formSelect->setTranslatorTextDomain('fid');
 $formRadio->setTranslatorTextDomain('fid');
 $formSubmit->setTranslatorTextDomain('fid');
 $formElementErrors->setTranslatorTextDomain('fid');
-/** @var TranslatorInterface $translator */
-$translator = $this->getHelperPluginManager()->get('translate')
-    ->getTranslator();
-
-$formLabel->setTranslator($translator);
-$formElementErrors->setTranslator($translator);
-
-/** @var Form $form */
-/** @var User $user */
-$user = $this->user;
-$form = $this->form;
-$form->setAttribute('method', 'post');
-$form->setAttribute('action', $this->url('fid/user/update'));
-$form->setAttribute('class', 'form-horizontal');
-$form->prepare();
-
-$this->headTitle($this->translate('Profile Form'));
-$this->headTitle($this->translate("fid::user_update_form_title"));
+$this->headTitle($title = $this->translate("fid::user_update_form_title"));
 ?>
 
-    <h2><?= $this->translate("fid::user_update_form_title") ?></h2>
+<h2><?= $title ?></h2>
+<div><?= $this->transEsc("fid::required_fields_note") ?></div>
 <?= $this->flashmessages() ?>
 <?= $this->form()->openTag($form) ?>
-    <br/>
+<br/>
 
-<? /* home library */ ?>
-<?php
-/** @var Element\Select $elemHomeLibrary */
-$elemHomeLibrary = $form->get('homeLibrary');
-$elemHomeLibrary->setLabelAttributes(['class' => 'inline col-md-4 col-sm-10']);
-$elemHomeLibrary->setAttributes(['class' => 'inline col-sm-6']);
-$elemHomeLibrary->setValue($elemHomeLibrary->getValue() ?? $user->getHomeLibrary());
-?>
-    <div class="form-group">
-        <?= $this->formLabel($elemHomeLibrary) ?>
-        <?= $this->formSelect($elemHomeLibrary) ?>
-        <?= $this->formElementErrors($elemHomeLibrary) ?>
-    </div>
+<? /* id */ ?>
+<?= $this->formElement($form->get('id')) ?>
 
 <? /* salutation */ ?>
 <?php
 /** @var Element\Select $elemSalutation */
 $elemSalutation = $form->get('salutation');
-$elemSalutation->setLabelAttributes(['class' => 'inline col-md-4 col-sm-10']);
-$elemSalutation->setAttributes(['class' => 'inline col-sm-2']);
-$elemSalutation->setValue($elemSalutation->getValue() ?? $user->getSalutation());
+$elemSalutation->setLabelAttributes(['class' => 'col-md-4']);
+$elemSalutation->setAttributes(['class' => 'form-control']);
 ?>
-    <div class="form-group">
-        <?= $this->formLabel($elemSalutation) ?>
-        <?= $this->formSelect($elemSalutation) ?>
-
-    </div>
+<div class="form-group">
+    <?= $this->formLabel($elemSalutation) ?>
+    <?= $this->formSelect($elemSalutation) ?>
+</div>
 
 <? /* academic title */ ?>
 <?php
 /** @var Element\Text $elemAcademicTitle */
-$elemAcademicTitle = $form->get('academicTitle');
-$elemAcademicTitle->setLabelAttributes(['class' => 'inline col-md-4 col-sm-10']);
+$elemAcademicTitle = $form->get('academic_title');
+$elemAcademicTitle->setLabelAttributes(['class' => 'col-md-4']);
 $elemAcademicTitle->setAttributes(['class' => 'form-control']);
-$elemAcademicTitle->setValue($elemAcademicTitle->getValue() ?? $user->getAcademicTitle());
 ?>
-    <div class="form-group">
-        <?= $this->formLabel($elemAcademicTitle) ?>
-        <?= $this->formElement($elemAcademicTitle) ?>
-    </div>
+<div class="form-group">
+    <?= $this->formLabel($elemAcademicTitle) ?>
+    <?= $this->formElement($elemAcademicTitle) ?>
+</div>
 
 <? /* firstname */ ?>
 <?php
 /** @var Element\Text $elemFirstname */
 $elemFirstname = $form->get('firstname');
-$elemFirstname->setLabelAttributes(['class' => 'inline col-md-4 col-sm-10']);
+$elemFirstname->setLabelAttributes(['class' => 'col-md-4']);
 $elemFirstname->setAttributes(['class' => 'form-control']);
-$elemFirstname->setValue($elemFirstname->getValue() ?? $user->getFirstname());
 ?>
-    <div class="form-group">
-        <?= $this->formLabel($elemFirstname) ?>
-        <?= $this->formElement($elemFirstname) ?>
-        <?= $this->formElementErrors($elemFirstname) ?>
-    </div>
+<div class="form-group">
+    <?= $this->formLabel($elemFirstname) ?>
+    <?= $this->formElement($elemFirstname) ?>
+    <?= $this->formElementErrors($elemFirstname) ?>
+</div>
 
 <? /* lastname */ ?>
 <?php
 /** @var Element\Text $elemLastname */
 $elemLastname = $form->get('lastname');
-$elemLastname->setLabelAttributes(['class' => 'inline col-md-4 col-sm-10']);
+$elemLastname->setLabelAttributes(['class' => 'col-md-4']);
 $elemLastname->setAttributes(['class' => 'form-control']);
-$elemLastname->setValue($elemLastname->getValue() ?? $user->getLastname());
 ?>
-    <div class="form-group">
-        <?= $this->formLabel($elemLastname) ?>
-        <?= $this->formElement($elemLastname) ?>
-        <?= $this->formElementErrors($elemLastname) ?>
-    </div>
+<div class="form-group">
+    <?= $this->formLabel($elemLastname) ?>
+    <?= $this->formElement($elemLastname) ?>
+    <?= $this->formElementErrors($elemLastname) ?>
+</div>
 
-<? /* year of birth */ ?>
+<? /* home library */ ?>
 <?php
-/** @var Element\Text $elemYearOfBirth */
-$elemYearOfBirth = $form->get('yearOfBirth');
-$elemYearOfBirth->setLabelAttributes(['class' => 'inline col-md-4 col-sm-10']);
-$elemYearOfBirth->setAttributes(['class' => 'form-control']);
-$elemYearOfBirth->setValue($elemYearOfBirth->getValue() ?? $user->getYearOfBirth());
+/** @var Element\Select $elemHomeLibrary */
+$elemHomeLibrary = $form->get('home_library');
+$elemHomeLibrary->setLabelAttributes(['class' => 'col-md-4']);
+$elemHomeLibrary->setAttributes(['class' => 'form-control']);
 ?>
-    <div class="form-group">
-        <?= $this->formLabel($elemYearOfBirth) ?>
-        <?= $this->formElement($elemYearOfBirth) ?>
-        <?= $this->formElementErrors($elemYearOfBirth) ?>
-    </div>
+<div class="form-group">
+    <?= $this->formLabel($elemHomeLibrary) ?>
+    <?= $this->formSelect($elemHomeLibrary) ?>
+    <?= $this->formElementErrors($elemHomeLibrary) ?>
+</div>
 
 <? /* college */ ?>
 <?php
 /** @var Element\Text $elemCollege */
 $elemCollege = $form->get('college');
-$elemCollege->setLabelAttributes(['class' => 'inline col-md-4 col-sm-10']);
+$elemCollege->setLabelAttributes(['class' => 'col-md-4']);
 $elemCollege->setAttributes(['class' => 'form-control']);
-$elemCollege->setValue($elemCollege->getValue() ?? $user->getCollege());
-?>
-    <div class="form-group">
-        <?= $this->formLabel($elemCollege) ?>
-        <?= $this->formElement($elemCollege) ?>
-        <?= $this->formElementErrors($elemCollege) ?>
-    </div>
-
-<? /* job title */ ?>
-<?php
-/** @var Element\Text $elemJobTitle */
-$elemJobTitle = $form->get('jobTitle');
-$elemJobTitle->setLabelAttributes(['class' => 'inline col-md-4 col-sm-10']);
-$elemJobTitle->setAttributes(['class' => 'form-control']);
-$elemJobTitle->setValue($elemJobTitle->getValue() ?? $user->getJobTitle());
 ?>
-    <div class="form-group">
-        <?= $this->formLabel($elemJobTitle) ?>
-        <?= $this->formElement($elemJobTitle) ?>
-        <?= $this->formElementErrors($elemJobTitle) ?>
-    </div>
+<div class="form-group">
+    <?= $this->formLabel($elemCollege) ?>
+    <?= $this->formElement($elemCollege) ?>
+    <?= $this->formElementErrors($elemCollege) ?>
+</div>
 
 <? /* addresses */ ?>
-<?= $this->render('update-addresses.phtml', compact('form', 'user')) ?>
+<?= $this->render('address-collection.phtml') ?>
 
 <? /* submit button */ ?>
 <?php
@@ -192,14 +143,14 @@ $elemJobTitle->setValue($elemJobTitle->getValue() ?? $user->getJobTitle());
 $elemSubmit = $form->get('submit');
 $elemSubmit->setAttributes(['class' => 'btn btn-primary']);
 ?>
-    <div class="form-group">
-        <div class="col-lg-11 col-md-9 col-sm-11 col-xs-12">
-            <?= $this->formSubmit($elemSubmit) ?>
-            <a href="<?= $this->url('myresearch-profile') ?>"
-               class="btn btn-primary">
-                <?= $this->transEsc('Cancel') ?>
-            </a>
-        </div>
+<div class="form-group">
+    <div class="col-lg-11 col-md-9 col-sm-11 col-xs-12">
+        <?= $this->formSubmit($elemSubmit) ?>
+        <a href="<?= $this->url('myresearch-profile') ?>"
+           class="btn btn-primary">
+            <?= $this->transEsc('Cancel') ?>
+        </a>
     </div>
+</div>
 
 <?= $this->form()->closeTag($form) ?>