diff --git a/lam/HISTORY b/lam/HISTORY
index f141e945b..5ab95b7ce 100644
--- a/lam/HISTORY
+++ b/lam/HISTORY
@@ -11,6 +11,7 @@ December 2024 9.0
  - Fixed bugs:
   -> Windows: show more than 1000 LDAP entries when paged results is activated in server profile
   -> WebAuthn: support DNs larger than 64 bytes (358)
+  -> Wildcard replacements do not work without switching to the module tab (379)
 
 
 24.09.2024 8.9
diff --git a/lam/lib/baseModule.inc b/lam/lib/baseModule.inc
index c132749be..00a88fccb 100644
--- a/lam/lib/baseModule.inc
+++ b/lam/lib/baseModule.inc
@@ -1228,6 +1228,7 @@ abstract class baseModule {
 	 * @return array list of modifications
 	 */
 	public function save_attributes() {
+		$this->getAccountContainer()->replaceWildcardsInArray($this->getWildcardTargetAttributeNames(), $this->attributes);
 		return $this->getAccountContainer()->save_module_attributes($this->attributes, $this->orig);
 	}
 
@@ -2365,6 +2366,15 @@ abstract class baseModule {
 		return [];
 	}
 
+	/**
+	 * Returns a list of attribute names that may contain wildcards.
+	 *
+	 * @return array list of attribute names
+	 */
+	public function getWildcardTargetAttributeNames(): array {
+		return [];
+	}
+
 	/**
 	 * Returns a callable if there should be a custom filtering for the given attribute name.
 	 *
diff --git a/lam/lib/modules/courierMailAccount.inc b/lam/lib/modules/courierMailAccount.inc
index 3fad75940..95eee1805 100644
--- a/lam/lib/modules/courierMailAccount.inc
+++ b/lam/lib/modules/courierMailAccount.inc
@@ -247,13 +247,20 @@ class courierMailAccount extends baseModule {
 		return $attrs;
 	}
 
+	/**
+	 * {@inheritdoc}
+	 */
+	public function getWildcardTargetAttributeNames(): array {
+		return ['homeDirectory', 'mailbox'];
+	}
+
 	/**
 	 * {@inheritDoc}
 	 */
 	public function display_html_attributes() {
 		$return = new htmlResponsiveRow();
 		if ($this->isExtensionEnabled()) {
-			$this->getAccountContainer()->replaceWildcardsInArray(['homeDirectory', 'mailbox'], $this->attributes);
+			$this->getAccountContainer()->replaceWildcardsInArray($this->getWildcardTargetAttributeNames(), $this->attributes);
 			if ($this->isUnixDisabled($this->getAccountContainer()->get_type()->getModules())) {
 				// home directory
 				$this->addSimpleInputTextField($return, 'homeDirectory', _('Home directory'), true);
@@ -334,7 +341,7 @@ class courierMailAccount extends baseModule {
 		if (!$this->isExtensionEnabled()) {
 			return [];
 		}
-		$this->getAccountContainer()->replaceWildcardsInPOST(['homeDirectory', 'mailbox']);
+		$this->getAccountContainer()->replaceWildcardsInPOST($this->getWildcardTargetAttributeNames());
 		$errors = [];
 		// check new mailbox
 		$this->attributes['mailbox'][0] = $_POST['mailbox'];
diff --git a/lam/lib/modules/inetLocalMailRecipient.inc b/lam/lib/modules/inetLocalMailRecipient.inc
index 363032ba7..ce869525e 100644
--- a/lam/lib/modules/inetLocalMailRecipient.inc
+++ b/lam/lib/modules/inetLocalMailRecipient.inc
@@ -186,6 +186,13 @@ class inetLocalMailRecipient extends baseModule {
 		}
 	}
 
+	/**
+	 * {@inheritdoc}
+	 */
+	public function getWildcardTargetAttributeNames(): array {
+		return ['mailLocalAddress', 'mailRoutingAddress'];
+	}
+
 	/**
 	 * Returns the HTML meta data for the main account page.
 	 *
@@ -194,7 +201,7 @@ class inetLocalMailRecipient extends baseModule {
 	function display_html_attributes() {
 		$return = new htmlResponsiveRow();
 		if (in_array('inetLocalMailRecipient', $this->attributes['objectClass'])) {
-			$this->getAccountContainer()->replaceWildcardsInArray(['mailLocalAddress', 'mailRoutingAddress'], $this->attributes);
+			$this->getAccountContainer()->replaceWildcardsInArray($this->getWildcardTargetAttributeNames(), $this->attributes);
 			// mail routing address
 			$this->addSimpleInputTextField($return, 'mailRoutingAddress', _('Routing address'));
 			// mail server
@@ -237,7 +244,7 @@ class inetLocalMailRecipient extends baseModule {
 			return [];
 		}
 		$errors = [];
-		$this->getAccountContainer()->replaceWildcardsInPOST(['mailLocalAddress', 'mailRoutingAddress']);
+		$this->getAccountContainer()->replaceWildcardsInPOST($this->getWildcardTargetAttributeNames());
 		$this->attributes['mailRoutingAddress'] = [];
 		$this->attributes['mailLocalAddress'] = [];
 		$this->attributes['mailHost'] = [];
diff --git a/lam/lib/modules/inetOrgPerson.inc b/lam/lib/modules/inetOrgPerson.inc
index 12a189908..1463d564e 100644
--- a/lam/lib/modules/inetOrgPerson.inc
+++ b/lam/lib/modules/inetOrgPerson.inc
@@ -892,7 +892,7 @@ class inetOrgPerson extends baseModule implements passwordService, AccountStatus
 		if (!$this->getAccountContainer()->isNewAccount && !in_array('inetOrgPerson', $this->getAccountContainer()->attributes_orig['objectClass'])) {
 			return [];
 		}
-		$return = $this->getAccountContainer()->save_module_attributes($this->attributes, $this->orig);
+		$return = parent::save_attributes();
 		// postalAddress, registeredAddress, facsimileTelephoneNumber and jpegPhoto need special removing
 		if (isset($return[$this->getAccountContainer()->dn_orig]['remove']['postalAddress'])) {
 			$return[$this->getAccountContainer()->dn_orig]['modify']['postalAddress'] = $this->attributes['postalAddress'];
@@ -999,12 +999,7 @@ class inetOrgPerson extends baseModule implements passwordService, AccountStatus
 	 */
 	function process_attributes() {
 		$errors = [];
-		$keysToReplace = ['mail', 'description', 'postalAddress', 'cn',
-			'registeredAddress', 'labeledURI'];
-		if ($this->isUnixActive()) {
-			$keysToReplace[] = 'uid';
-		}
-		$this->getAccountContainer()->replaceWildcardsInPOST($keysToReplace);
+		$this->getAccountContainer()->replaceWildcardsInPOST($this->getWildcardTargetAttributeNames());
 		// add parent object classes
 		if ($this->getAccountContainer()->isNewAccount) {
 			if (!in_array('organizationalPerson', $this->attributes['objectClass'])) {
@@ -1218,12 +1213,7 @@ class inetOrgPerson extends baseModule implements passwordService, AccountStatus
 	 */
 	function display_html_attributes() {
 		$this->initCache();
-		$keysToReplace = ['mail', 'description', 'postalAddress', 'uid', 'cn',
-			'registeredAddress', 'labeledURI'];
-		if ($this->isUnixActive()) {
-			$keysToReplace[] = 'uid';
-		}
-		$this->getAccountContainer()->replaceWildcardsInArray($keysToReplace, $this->attributes);
+		$this->getAccountContainer()->replaceWildcardsInArray($this->getWildcardTargetAttributeNames(), $this->attributes);
 		$container = new htmlResponsiveRow();
 		$fieldContainer = new htmlResponsiveRow();
 		$fieldTabletColumns = $this->isBooleanConfigOptionSet('inetOrgPerson_hidejpegPhoto') ? 12 : 8;
@@ -3888,6 +3878,18 @@ class inetOrgPerson extends baseModule implements passwordService, AccountStatus
 		return in_array('sambaSamAccount', $modules);
 	}
 
+	/**
+	 * {@inheritdoc}
+	 */
+	public function getWildcardTargetAttributeNames(): array {
+		$attributeNames = ['mail', 'description', 'postalAddress', 'uid', 'cn',
+			'registeredAddress', 'labeledURI'];
+		if ($this->isUnixActive()) {
+			$attributeNames[] = 'uid';
+		}
+		return $attributeNames;
+	}
+
 	/**
 	 * {@inheritdoc}
 	 */
diff --git a/lam/lib/modules/posixAccount.inc b/lam/lib/modules/posixAccount.inc
index cc94a7dff..0511edfc7 100644
--- a/lam/lib/modules/posixAccount.inc
+++ b/lam/lib/modules/posixAccount.inc
@@ -669,7 +669,7 @@ class posixAccount extends baseModule implements passwordService, AccountStatusP
 		}
 		$modules = $this->getAccountContainer()->get_type()->getModules();
 		// get default changes
-		$return = $this->getAccountContainer()->save_module_attributes($this->attributes, $this->orig);
+		$return = parent::save_attributes();
 		// add information about clear text password and password status change
 		$return[$this->getAccountContainer()->dn_orig]['info']['userPasswordClearText'][0] = $this->clearTextPassword;
 		$pwdAttrName = $this->getPasswordAttrName($modules);
@@ -1091,8 +1091,7 @@ class posixAccount extends baseModule implements passwordService, AccountStatusP
 	 * @return array list of info/error messages
 	 */
 	function process_attributes() {
-		$keysToReplace = ['cn', 'gecos', 'homeDirectory'];
-		$this->getAccountContainer()->replaceWildcardsInPOST($keysToReplace);
+		$this->getAccountContainer()->replaceWildcardsInPOST($this->getWildcardTargetAttributeNames());
 		$modules = $this->getAccountContainer()->get_type()->getModules();
 		$typeId = $this->getAccountContainer()->get_type()->getId();
 		$errors = [];
@@ -1695,6 +1694,13 @@ class posixAccount extends baseModule implements passwordService, AccountStatusP
 		return $return;
 	}
 
+	/**
+	 * {@inheritdoc}
+	 */
+	public function getWildcardTargetAttributeNames(): array {
+		return ['cn', 'gecos', 'homeDirectory'];
+	}
+
 	/**
 	 * Returns the HTML meta data for the main account page.
 	 *
@@ -1706,8 +1712,7 @@ class posixAccount extends baseModule implements passwordService, AccountStatusP
 		$modules = $this->getAccountContainer()->get_type()->getModules();
 		$typeId = $this->getAccountContainer()->get_type()->getId();
 		if (!$this->isOptional($modules) || $this->skipObjectClass() || (isset($this->attributes['objectClass']) && in_array('posixAccount', $this->attributes['objectClass']))) {
-			$keysToReplace = ['cn', 'gecos', 'homeDirectory'];
-			$this->getAccountContainer()->replaceWildcardsInArray($keysToReplace, $this->attributes);
+			$this->getAccountContainer()->replaceWildcardsInArray($this->getWildcardTargetAttributeNames(), $this->attributes);
 			$homeDirAttr = $this->getHomedirAttrName($modules);
 			$groupList = $this->findGroups($modules); // list of all group names
 			$groups = [];
diff --git a/lam/lib/modules/windowsUser.inc b/lam/lib/modules/windowsUser.inc
index 63d5b1a2b..ab90852ec 100644
--- a/lam/lib/modules/windowsUser.inc
+++ b/lam/lib/modules/windowsUser.inc
@@ -1342,6 +1342,15 @@ class windowsUser extends baseModule implements passwordService, AccountStatusPr
 		return $return;
 	}
 
+	/**
+	 * {@inheritdoc}
+	 */
+	public function getWildcardTargetAttributeNames(): array {
+		return ['cn', 'displayName', 'mail', 'otherMailbox',
+			'profilePath', 'scriptPath', 'homeDirectory', 'userPrincipalName',
+			'sAMAccountName'];
+	}
+
 	/**
 	 * Returns the HTML metadata for the main account page.
 	 *
@@ -1349,10 +1358,7 @@ class windowsUser extends baseModule implements passwordService, AccountStatusPr
 	 */
 	public function display_html_attributes() {
 		$this->initCache();
-		$keysToReplace = ['cn', 'displayName', 'mail', 'otherMailbox',
-			'profilePath', 'scriptPath', 'homeDirectory', 'userPrincipalName',
-			'sAMAccountName'];
-		$this->getAccountContainer()->replaceWildcardsInArray($keysToReplace, $this->attributes);
+		$this->getAccountContainer()->replaceWildcardsInArray($this->getWildcardTargetAttributeNames(), $this->attributes);
 		$containerLeft = new htmlResponsiveRow();
 		if ($this->getAccountContainer()->isNewAccount && !isset($this->attributes['useraccountcontrol'][0])) {
 			$this->attributes['useraccountcontrol'][0] = self::DEFAULT_ACCOUNT_CONTROL;
@@ -1744,10 +1750,7 @@ class windowsUser extends baseModule implements passwordService, AccountStatusPr
 	 */
 	public function process_attributes() {
 		$return = [];
-		$keysToReplace = ['cn', 'displayName', 'mail', 'otherMailbox',
-			'profilePath', 'scriptPath', 'homeDirectory', 'userPrincipalName',
-			'sAMAccountName'];
-		$this->getAccountContainer()->replaceWildcardsInPOST($keysToReplace);
+		$this->getAccountContainer()->replaceWildcardsInPOST($this->getWildcardTargetAttributeNames());
 		// user name
 		$userPrincipalName = $_POST['userPrincipalName'];
 		if (!get_preg($userPrincipalName, 'username')) {