diff --git a/src/eduid/webapp/personal_data/schemas.py b/src/eduid/webapp/personal_data/schemas.py
index 24721c1c5..5443aa708 100644
--- a/src/eduid/webapp/personal_data/schemas.py
+++ b/src/eduid/webapp/personal_data/schemas.py
@@ -28,6 +28,28 @@ class PersonalDataSchema(EduidSchema):
     language = fields.String(required=True, attribute="preferredLanguage")
 
 
+class UserNameRequestSchema(EduidSchema, CSRFRequestMixin):
+    given_name = fields.String(required=True, validate=[validate_nonempty])
+    chosen_given_name = fields.String(required=False)
+    surname = fields.String(required=True, validate=[validate_nonempty])
+    legal_name = fields.String(required=False)
+
+
+class UserNameSchema(EduidSchema):
+    given_name = fields.String(required=True, attribute="givenName")
+    chosen_given_name = fields.String(required=False)
+    surname = fields.String(required=True)
+    legal_name = fields.String(required=False)
+
+
+class UserLanguageRequestSchema(EduidSchema, CSRFRequestMixin):
+    language = fields.String(required=True, default="en", validate=validate_language)
+
+
+class UserLanguageSchema(EduidSchema):
+    language = fields.String(required=True, attribute="preferredLanguage")
+
+
 class UserPreferencesSchema(EduidSchema):
     always_use_security_key = fields.Boolean(required=True, default=True)
 
@@ -50,6 +72,20 @@ class PersonalDataResponsePayload(PersonalDataSchema, CSRFResponseMixin):
     payload = fields.Nested(PersonalDataResponsePayload)
 
 
+class UserNameResponseSchema(FluxStandardAction):
+    class UserNameResponsePayload(UserNameSchema, CSRFResponseMixin):
+        pass
+
+    payload = fields.Nested(UserNameResponsePayload)
+
+
+class UserLanguageResponseSchema(FluxStandardAction):
+    class UserLanguageResponsePayload(UserLanguageSchema, CSRFResponseMixin):
+        pass
+
+    payload = fields.Nested(UserLanguageResponsePayload)
+
+
 class IdentitiesResponseSchema(FluxStandardAction):
     class IdentitiesResponsePayload(EmailSchema, CSRFResponseMixin):
         identities = fields.Nested(IdentitiesSchema)
diff --git a/src/eduid/webapp/personal_data/tests/test_app.py b/src/eduid/webapp/personal_data/tests/test_app.py
index 25aefca65..dffed9eb8 100644
--- a/src/eduid/webapp/personal_data/tests/test_app.py
+++ b/src/eduid/webapp/personal_data/tests/test_app.py
@@ -93,6 +93,56 @@ def _post_user(
                     data.update(mod_data)
             return client.post("/user", data=json.dumps(data), content_type=self.content_type_json)
 
+    @patch("eduid.common.rpc.am_relay.AmRelay.request_user_sync")
+    def _post_user_name(
+        self, mock_request_user_sync: Any, mod_data: dict[str, Any] | None = None, verified_user: bool = True
+    ):
+        """
+        POST user name for the test user
+        """
+        mock_request_user_sync.side_effect = self.request_user_sync
+        eppn = self.test_user_data["eduPersonPrincipalName"]
+
+        if not verified_user:
+            # Remove verified identities from the users
+            user = self.app.central_userdb.get_user_by_eppn(eppn)
+            for identity in user.identities.verified:
+                user.identities.remove(ElementKey(identity.identity_type.value))
+            self.app.central_userdb.save(user)
+
+        with self.session_cookie(self.browser, eppn) as client:
+            with self.app.test_request_context():
+                with client.session_transaction() as sess:
+                    data = {
+                        "given_name": "Peter",
+                        "surname": "Johnson",
+                        "csrf_token": sess.get_csrf_token(),
+                    }
+                if mod_data:
+                    data.update(mod_data)
+            return client.post("/user/name", data=json.dumps(data), content_type=self.content_type_json)
+
+    @patch("eduid.common.rpc.am_relay.AmRelay.request_user_sync")
+    def _post_user_language(
+        self, mock_request_user_sync: Any, mod_data: dict[str, Any] | None = None, verified_user: bool = True
+    ):
+        """
+        POST user language for the test user
+        """
+        mock_request_user_sync.side_effect = self.request_user_sync
+        eppn = self.test_user_data["eduPersonPrincipalName"]
+
+        with self.session_cookie(self.browser, eppn) as client:
+            with self.app.test_request_context():
+                with client.session_transaction() as sess:
+                    data = {
+                        "language": "en",
+                        "csrf_token": sess.get_csrf_token(),
+                    }
+                if mod_data:
+                    data.update(mod_data)
+            return client.post("/user/language", data=json.dumps(data), content_type=self.content_type_json)
+
     def _get_preferences(self, eppn: str | None = None):
         """
         Send a GET request to get the personal data of a user
@@ -207,6 +257,23 @@ def test_post_user(self):
         }
         self._check_success_response(response, type_="POST_PERSONAL_DATA_USER_SUCCESS", payload=expected_payload)
 
+    def test_post_user_name(self):
+        response = self._post_user_name(verified_user=False)
+        expected_payload = {
+            "surname": "Johnson",
+            "given_name": "Peter",
+        }
+        self._check_success_response(response, type_="POST_PERSONAL_DATA_USER_NAME_SUCCESS", payload=expected_payload)
+
+    def test_post_user_language(self):
+        response = self._post_user_language(verified_user=False)
+        expected_payload = {
+            "language": "en",
+        }
+        self._check_success_response(
+            response, type_="POST_PERSONAL_DATA_USER_LANGUAGE_SUCCESS", payload=expected_payload
+        )
+
     def test_set_chosen_given_name_and_language_verified_user(self):
         expected_payload = {
             "surname": "Smith",
@@ -216,6 +283,23 @@ def test_set_chosen_given_name_and_language_verified_user(self):
         response = self._post_user(mod_data=expected_payload)
         self._check_success_response(response, type_="POST_PERSONAL_DATA_USER_SUCCESS", payload=expected_payload)
 
+    def test_post_user_name_set_chosen_given_name_verified_user(self):
+        expected_payload = {
+            "surname": "Smith",
+            "given_name": "John",
+        }
+        response = self._post_user_name(mod_data=expected_payload)
+        self._check_success_response(response, type_="POST_PERSONAL_DATA_USER_NAME_SUCCESS", payload=expected_payload)
+
+    def test_post_user_language_set_language_verified_user(self):
+        expected_payload = {
+            "language": "sv",
+        }
+        response = self._post_user_language(mod_data=expected_payload)
+        self._check_success_response(
+            response, type_="POST_PERSONAL_DATA_USER_LANGUAGE_SUCCESS", payload=expected_payload
+        )
+
     def test_set_given_name_and_surname_verified_user(self):
         mod_data = {
             "surname": "Johnson",
@@ -230,31 +314,68 @@ def test_set_given_name_and_surname_verified_user(self):
         response = self._post_user(mod_data=mod_data)
         self._check_success_response(response, type_="POST_PERSONAL_DATA_USER_SUCCESS", payload=expected_payload)
 
+    def test_post_user_name_set_given_name_and_surname_verified_user(self):
+        mod_data = {
+            "surname": "Johnson",
+            "given_name": "Peter",
+        }
+        expected_payload = {
+            "surname": "Smith",
+            "given_name": "John",
+        }
+        response = self._post_user_name(mod_data=mod_data)
+        self._check_success_response(response, type_="POST_PERSONAL_DATA_USER_NAME_SUCCESS", payload=expected_payload)
+
     def test_post_user_bad_csrf(self):
         response = self._post_user(mod_data={"csrf_token": "wrong-token"})
         expected_payload = {"error": {"csrf_token": ["CSRF failed to validate"]}}
         self._check_error_response(response, type_="POST_PERSONAL_DATA_USER_FAIL", payload=expected_payload)
 
+    def test_post_user__name_bad_csrf(self):
+        response = self._post_user_name(mod_data={"csrf_token": "wrong-token"})
+        expected_payload = {"error": {"csrf_token": ["CSRF failed to validate"]}}
+        self._check_error_response(response, type_="POST_PERSONAL_DATA_USER_NAME_FAIL", payload=expected_payload)
+
     def test_post_user_no_given_name(self):
         response = self._post_user(mod_data={"given_name": ""})
         expected_payload = {"error": {"given_name": ["pdata.field_required"]}}
         self._check_error_response(response, type_="POST_PERSONAL_DATA_USER_FAIL", payload=expected_payload)
 
+    def test_post_user_name_no_given_name(self):
+        response = self._post_user_name(mod_data={"given_name": ""})
+        expected_payload = {"error": {"given_name": ["pdata.field_required"]}}
+        self._check_error_response(response, type_="POST_PERSONAL_DATA_USER_NAME_FAIL", payload=expected_payload)
+
     def test_post_user_blank_given_name(self):
         response = self._post_user(mod_data={"given_name": " "})
         expected_payload = {"error": {"given_name": ["pdata.field_required"]}}
         self._check_error_response(response, type_="POST_PERSONAL_DATA_USER_FAIL", payload=expected_payload)
 
+    def test_post_user_name_blank_given_name(self):
+        response = self._post_user_name(mod_data={"given_name": " "})
+        expected_payload = {"error": {"given_name": ["pdata.field_required"]}}
+        self._check_error_response(response, type_="POST_PERSONAL_DATA_USER_NAME_FAIL", payload=expected_payload)
+
     def test_post_user_no_surname(self):
         response = self._post_user(mod_data={"surname": ""})
         expected_payload = {"error": {"surname": ["pdata.field_required"]}}
         self._check_error_response(response, type_="POST_PERSONAL_DATA_USER_FAIL", payload=expected_payload)
 
+    def test_post_user_name_no_surname(self):
+        response = self._post_user_name(mod_data={"surname": ""})
+        expected_payload = {"error": {"surname": ["pdata.field_required"]}}
+        self._check_error_response(response, type_="POST_PERSONAL_DATA_USER_NAME_FAIL", payload=expected_payload)
+
     def test_post_user_blank_surname(self):
         response = self._post_user(mod_data={"surname": " "})
         expected_payload = {"error": {"surname": ["pdata.field_required"]}}
         self._check_error_response(response, type_="POST_PERSONAL_DATA_USER_FAIL", payload=expected_payload)
 
+    def test_post_user_name_blank_surname(self):
+        response = self._post_user_name(mod_data={"surname": " "})
+        expected_payload = {"error": {"surname": ["pdata.field_required"]}}
+        self._check_error_response(response, type_="POST_PERSONAL_DATA_USER_NAME_FAIL", payload=expected_payload)
+
     def test_post_user_with_chosen_given_name(self):
         response = self._post_user(mod_data={"chosen_given_name": "Peter"}, verified_user=False)
         expected_payload = {
@@ -265,12 +386,27 @@ def test_post_user_with_chosen_given_name(self):
         }
         self._check_success_response(response, type_="POST_PERSONAL_DATA_USER_SUCCESS", payload=expected_payload)
 
+    def test_post_user_name_with_chosen_given_name(self):
+        response = self._post_user_name(mod_data={"chosen_given_name": "Peter"}, verified_user=False)
+        expected_payload = {
+            "surname": "Johnson",
+            "given_name": "Peter",
+            "chosen_given_name": "Peter",
+        }
+        self._check_success_response(response, type_="POST_PERSONAL_DATA_USER_NAME_SUCCESS", payload=expected_payload)
+
     def test_post_user_with_bad_chosen_given_name(self):
         response = self._post_user(mod_data={"chosen_given_name": "Michael"}, verified_user=False)
         self._check_error_response(
             response, type_="POST_PERSONAL_DATA_USER_FAIL", msg=PDataMsg.chosen_given_name_invalid
         )
 
+    def test_post_user_name_with_bad_chosen_given_name(self):
+        response = self._post_user_name(mod_data={"chosen_given_name": "Michael"}, verified_user=False)
+        self._check_error_response(
+            response, type_="POST_PERSONAL_DATA_USER_NAME_FAIL", msg=PDataMsg.chosen_given_name_invalid
+        )
+
     def test_post_user_to_unset_chosen_given_name(self):
         # set test user chosen given name
         self.test_user.chosen_given_name = "Peter"
@@ -286,16 +422,40 @@ def test_post_user_to_unset_chosen_given_name(self):
         }
         self._check_success_response(response, type_="POST_PERSONAL_DATA_USER_SUCCESS", payload=expected_payload)
 
+    def test_post_user_name_to_unset_chosen_given_name(self):
+        # set test user chosen given name
+        self.test_user.chosen_given_name = "Peter"
+        self.app.central_userdb.save(self.test_user)
+        user = self.app.central_userdb.get_user_by_eppn(eppn=self.test_user.eppn)
+        assert user.chosen_given_name == "Peter"
+
+        response = self._post_user_name(verified_user=False)
+        expected_payload = {
+            "surname": "Johnson",
+            "given_name": "Peter",
+        }
+        self._check_success_response(response, type_="POST_PERSONAL_DATA_USER_NAME_SUCCESS", payload=expected_payload)
+
     def test_post_user_no_language(self):
         response = self._post_user(mod_data={"language": ""})
         expected_payload = {"error": {"language": ["Language '' is not available"]}}
         self._check_error_response(response, type_="POST_PERSONAL_DATA_USER_FAIL", payload=expected_payload)
 
+    def test_post_user_language_no_language(self):
+        response = self._post_user_language(mod_data={"language": ""})
+        expected_payload = {"error": {"language": ["Language '' is not available"]}}
+        self._check_error_response(response, type_="POST_PERSONAL_DATA_USER_LANGUAGE_FAIL", payload=expected_payload)
+
     def test_post_user_unknown_language(self):
         response = self._post_user(mod_data={"language": "es"})
         expected_payload = {"error": {"language": ["Language 'es' is not available"]}}
         self._check_error_response(response, type_="POST_PERSONAL_DATA_USER_FAIL", payload=expected_payload)
 
+    def test_post_user_language_unknown_language(self):
+        response = self._post_user_language(mod_data={"language": "es"})
+        expected_payload = {"error": {"language": ["Language 'es' is not available"]}}
+        self._check_error_response(response, type_="POST_PERSONAL_DATA_USER_LANGUAGE_FAIL", payload=expected_payload)
+
     def test_get_preferences(self):
         response = self._get_preferences()
         expected_payload = {"always_use_security_key": True}
diff --git a/src/eduid/webapp/personal_data/views.py b/src/eduid/webapp/personal_data/views.py
index e45d5f961..96d46716b 100644
--- a/src/eduid/webapp/personal_data/views.py
+++ b/src/eduid/webapp/personal_data/views.py
@@ -1,6 +1,7 @@
 from flask import Blueprint
 
 from eduid.common.config.base import FrontendAction
+from eduid.common.decorators import deprecated
 from eduid.userdb import User
 from eduid.userdb.exceptions import UserOutOfSync
 from eduid.userdb.personal_data import PersonalDataUser
@@ -14,6 +15,10 @@
     IdentitiesResponseSchema,
     PersonalDataRequestSchema,
     PersonalDataResponseSchema,
+    UserLanguageRequestSchema,
+    UserLanguageResponseSchema,
+    UserNameRequestSchema,
+    UserNameResponseSchema,
     UserPreferencesRequestSchema,
     UserPreferencesResponseSchema,
 )
@@ -44,6 +49,7 @@ def get_user(user: User) -> FluxData:
     return success_response(payload=user.to_dict())
 
 
+@deprecated("update_personal_data view is deprecated, use update_user_name or update_user_language view instead")
 @pd_views.route("/user", methods=["POST"])
 @UnmarshalWith(PersonalDataRequestSchema)
 @MarshalWith(PersonalDataResponseSchema)
@@ -83,6 +89,63 @@ def update_personal_data(
     return success_response(payload=personal_data, message=PDataMsg.save_success)
 
 
+@pd_views.route("/user/name", methods=["POST"])
+@UnmarshalWith(UserNameRequestSchema)
+@MarshalWith(UserNameResponseSchema)
+@require_user
+def update_user_name(user: User, given_name: str, surname: str, chosen_given_name: str | None = None) -> FluxData:
+    personal_data_user = PersonalDataUser.from_user(user, current_app.private_userdb)
+    current_app.logger.debug(f"Trying to save user {user}")
+
+    # disallow change of first name, surname if the user is verified
+    if not user.identities.is_verified:
+        personal_data_user.given_name = given_name
+        personal_data_user.surname = surname
+
+    # set chosen given name to either given name or a subset of given name if supplied
+    # also allow to set chosen given name to None
+    if (
+        chosen_given_name is not None
+        and is_valid_chosen_given_name(personal_data_user.given_name, chosen_given_name) is False
+    ):
+        return error_response(message=PDataMsg.chosen_given_name_invalid)
+
+    # mypy borked?
+    # error: Incompatible types in assignment (expression has type "str | None", variable has type "str")
+    personal_data_user.chosen_given_name = chosen_given_name
+
+    try:
+        save_and_sync_user(personal_data_user)
+    except UserOutOfSync:
+        return error_response(message=CommonMsg.out_of_sync)
+    current_app.stats.count(name="user_name_saved", value=1)
+    current_app.logger.info(f"Saved personal data for user {personal_data_user}")
+
+    personal_data = personal_data_user.to_dict()
+    return success_response(payload=personal_data, message=PDataMsg.save_success)
+
+
+@pd_views.route("/user/language", methods=["POST"])
+@UnmarshalWith(UserLanguageRequestSchema)
+@MarshalWith(UserLanguageResponseSchema)
+@require_user
+def update_user_language(user: User, language: str) -> FluxData:
+    personal_data_user = PersonalDataUser.from_user(user, current_app.private_userdb)
+    current_app.logger.debug(f"Trying to save user {user}")
+
+    personal_data_user.language = language
+
+    try:
+        save_and_sync_user(personal_data_user)
+    except UserOutOfSync:
+        return error_response(message=CommonMsg.out_of_sync)
+    current_app.stats.count(name="user_language_saved", value=1)
+    current_app.logger.info(f"Saved personal data for user {personal_data_user}")
+
+    personal_data = personal_data_user.to_dict()
+    return success_response(payload=personal_data, message=PDataMsg.save_success)
+
+
 @pd_views.route("/preferences", methods=["GET"])
 @MarshalWith(UserPreferencesResponseSchema)
 @require_user