diff --git a/components/org.wso2.carbon.identity.governance/src/main/java/org/wso2/carbon/identity/governance/IdentityGovernanceServiceImpl.java b/components/org.wso2.carbon.identity.governance/src/main/java/org/wso2/carbon/identity/governance/IdentityGovernanceServiceImpl.java
index 1c320016e..63b51ed0e 100644
--- a/components/org.wso2.carbon.identity.governance/src/main/java/org/wso2/carbon/identity/governance/IdentityGovernanceServiceImpl.java
+++ b/components/org.wso2.carbon.identity.governance/src/main/java/org/wso2/carbon/identity/governance/IdentityGovernanceServiceImpl.java
@@ -56,6 +56,9 @@ public class IdentityGovernanceServiceImpl implements IdentityGovernanceService
     private static final String EMAIL_LINK_PASSWORD_RECOVERY_PROPERTY
             = "Recovery.Notification.Password.emailLink.Enable";
     private static final String SMS_OTP_PASSWORD_RECOVERY_PROPERTY = "Recovery.Notification.Password.smsOtp.Enable";
+    private static final String USERNAME_RECOVERY_ENABLE = "Recovery.Notification.Username.Enable";
+    private  static final String USERNAME_RECOVERY_EMAIL_ENABLE = "Recovery.Notification.Username.Email.Enable";
+    private static final String USERNAME_RECOVERY_SMS_ENABLE = "Recovery.Notification.Username.SMS.Enable";
     private static final String FALSE_STRING = "false";
 
     public void updateConfiguration(String tenantDomain, Map<String, String> configurationDetails)
@@ -70,6 +73,7 @@ public void updateConfiguration(String tenantDomain, Map<String, String> configu
             updateEmailOTPNumericPropertyValue(configurationDetails);
             IdPManagementUtil.validatePasswordRecoveryPropertyValues(configurationDetails);
             updatePasswordRecoveryPropertyValues(configurationDetails, identityMgtProperties);
+            updateUsernameRecoveryPropertyValues(configurationDetails, identityMgtProperties);
             for (IdentityProviderProperty identityMgtProperty : identityMgtProperties) {
                 IdentityProviderProperty prop = new IdentityProviderProperty();
                 String key = identityMgtProperty.getName();
@@ -407,4 +411,63 @@ private void updatePasswordRecoveryPropertyValues(Map<String, String> configurat
             }
         }
     }
+
+    /**
+     * This method updates the username recovery property values based on the new configurations.
+     *
+     * @param configurationDetails    Updating configuration details of the resident identity provider.
+     * @param identityMgtProperties   Identity management properties of the resident identity provider.
+     */
+    private void updateUsernameRecoveryPropertyValues(Map<String, String> configurationDetails,
+                                                      IdentityProviderProperty[] identityMgtProperties) {
+
+        if (configurationDetails.containsKey(USERNAME_RECOVERY_ENABLE) ||
+                configurationDetails.containsKey(USERNAME_RECOVERY_EMAIL_ENABLE) ||
+                configurationDetails.containsKey(USERNAME_RECOVERY_SMS_ENABLE)) {
+
+            String usernameRecoveryProp = configurationDetails.get(USERNAME_RECOVERY_ENABLE);
+            String usernameRecoveryEmailProp = configurationDetails.get(USERNAME_RECOVERY_EMAIL_ENABLE);
+            String usernameRecoverySmsProp = configurationDetails.get(USERNAME_RECOVERY_SMS_ENABLE);
+
+            boolean usernameRecoveryProperty = Boolean.parseBoolean(usernameRecoveryProp);
+            boolean usernameRecoveryEmailProperty = Boolean.parseBoolean(usernameRecoveryEmailProp);
+            boolean usernameRecoverySmsProperty = Boolean.parseBoolean(usernameRecoverySmsProp);
+
+            if(usernameRecoveryProperty) {
+                configurationDetails.put(USERNAME_RECOVERY_EMAIL_ENABLE,
+                        String.valueOf(usernameRecoveryEmailProperty ||
+                                StringUtils.isBlank(usernameRecoveryEmailProp)));
+                configurationDetails.put(USERNAME_RECOVERY_SMS_ENABLE,
+                        String.valueOf(usernameRecoverySmsProperty ||
+                                StringUtils.isBlank(usernameRecoverySmsProp)));
+            } else if (StringUtils.isBlank(usernameRecoveryProp)) {
+                // Connector is not explicitly enabled or disabled. The connector state is derived from new and existing
+                // configurations.
+                boolean isUsernameEmailRecoveryCurrentlyEnabled = false;
+                boolean isUsernameSmsRecoveryCurrentlyEnabled = false;
+                for (IdentityProviderProperty identityMgtProperty : identityMgtProperties) {
+                    if (USERNAME_RECOVERY_EMAIL_ENABLE.equals(identityMgtProperty.getName())) {
+                        isUsernameEmailRecoveryCurrentlyEnabled = Boolean.parseBoolean(identityMgtProperty.getValue());
+                    } else if (USERNAME_RECOVERY_SMS_ENABLE.equals(identityMgtProperty.getName())) {
+                        isUsernameSmsRecoveryCurrentlyEnabled = Boolean.parseBoolean(identityMgtProperty.getValue());
+                    }
+                }
+                boolean enableUsernameEmailRecovery = usernameRecoveryEmailProperty ||
+                        ( StringUtils.isBlank(usernameRecoveryEmailProp) &&
+                                isUsernameEmailRecoveryCurrentlyEnabled );
+                boolean enableUsernameSmsRecovery = usernameRecoverySmsProperty ||
+                        ( StringUtils.isBlank(usernameRecoverySmsProp) &&
+                                isUsernameSmsRecoveryCurrentlyEnabled );
+                configurationDetails.put(USERNAME_RECOVERY_EMAIL_ENABLE,
+                        String.valueOf(enableUsernameEmailRecovery));
+                configurationDetails.put(USERNAME_RECOVERY_SMS_ENABLE,
+                        String.valueOf(enableUsernameSmsRecovery));
+                configurationDetails.put(USERNAME_RECOVERY_ENABLE,
+                        String.valueOf(enableUsernameEmailRecovery || enableUsernameSmsRecovery));
+            } else {
+                configurationDetails.put(USERNAME_RECOVERY_EMAIL_ENABLE, FALSE_STRING);
+                configurationDetails.put(USERNAME_RECOVERY_SMS_ENABLE, FALSE_STRING);
+            }
+        }
+    }
 }
diff --git a/components/org.wso2.carbon.identity.governance/src/test/java/org/wso2/carbon/identity/governance/IdentityGovernanceServiceImplTest.java b/components/org.wso2.carbon.identity.governance/src/test/java/org/wso2/carbon/identity/governance/IdentityGovernanceServiceImplTest.java
new file mode 100644
index 000000000..d080d8a5e
--- /dev/null
+++ b/components/org.wso2.carbon.identity.governance/src/test/java/org/wso2/carbon/identity/governance/IdentityGovernanceServiceImplTest.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.org)
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ *  Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.wso2.carbon.identity.governance;
+
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockedStatic;
+import org.mockito.MockitoAnnotations;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import org.wso2.carbon.identity.application.common.model.FederatedAuthenticatorConfig;
+import org.wso2.carbon.identity.application.common.model.IdentityProvider;
+import org.wso2.carbon.identity.application.common.model.IdentityProviderProperty;
+import org.wso2.carbon.identity.governance.internal.IdentityMgtServiceDataHolder;
+import org.wso2.carbon.idp.mgt.IdentityProviderManagementException;
+import org.wso2.carbon.idp.mgt.IdpManager;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.testng.AssertJUnit.assertEquals;
+
+public class IdentityGovernanceServiceImplTest {
+
+    // Constants.
+    private static final String TENANT_DOMAIN = "carbon.super";
+    private static final String TRUE_STRING = "true";
+    private static final String FALSE_STRING = "false";
+    private static final String USERNAME_RECOVERY_ENABLE = "Recovery.Notification.Username.Enable";
+    private static final String USERNAME_RECOVERY_EMAIL_ENABLE = "Recovery.Notification.Username.Email.Enable";
+    private static final String USERNAME_RECOVERY_SMS_ENABLE = "Recovery.Notification.Username.SMS.Enable";
+
+    @Mock
+    IdentityMgtServiceDataHolder identityMgtServiceDataHolder;
+
+    @Mock
+    IdpManager idpManager;
+
+    @Mock
+    IdentityProvider identityProvider;
+
+    MockedStatic<IdentityMgtServiceDataHolder> identityMgtServiceDataHolderMockedStatic;
+
+    private IdentityGovernanceServiceImpl identityGovernanceService;
+
+    @BeforeMethod
+    public void setup() throws IdentityProviderManagementException {
+
+        MockitoAnnotations.openMocks(this);
+        identityMgtServiceDataHolderMockedStatic = mockStatic(IdentityMgtServiceDataHolder.class);
+        identityMgtServiceDataHolderMockedStatic.when(IdentityMgtServiceDataHolder::
+                getInstance).thenReturn(identityMgtServiceDataHolder);
+        when(identityMgtServiceDataHolder.getIdpManager()).thenReturn(idpManager);
+        when(idpManager.getResidentIdP(TENANT_DOMAIN)).thenReturn(identityProvider);
+
+        FederatedAuthenticatorConfig[] authenticatorConfigs = new FederatedAuthenticatorConfig[0];
+        when(identityProvider.getFederatedAuthenticatorConfigs()).thenReturn(authenticatorConfigs);
+
+        identityGovernanceService = new IdentityGovernanceServiceImpl();
+    }
+
+    @AfterMethod
+    public void tearDown() {
+
+        identityMgtServiceDataHolderMockedStatic.close();
+    }
+
+    @Test(dataProvider = "updateConfigurations")
+    public void testUpdateConfiguration(Map<String, String> configurationDetails,
+                                        IdentityProviderProperty[] identityProviderProperties,
+                                        Map<String, String> expected) throws IdentityGovernanceException {
+
+        when(identityProvider.getIdpProperties()).thenReturn(identityProviderProperties);
+
+        identityGovernanceService.updateConfiguration(TENANT_DOMAIN, configurationDetails);
+
+        // Capture the arguments passed to setIdpProperties
+        ArgumentCaptor<IdentityProviderProperty[]>
+                argumentCaptor = ArgumentCaptor.forClass(IdentityProviderProperty[].class);
+        verify(identityProvider).setIdpProperties(argumentCaptor.capture());
+
+        // Assert
+        IdentityProviderProperty[] capturedProperties = argumentCaptor.getValue();
+        for (IdentityProviderProperty capturedProperty : capturedProperties) {
+            assertEquals(expected.get(capturedProperty.getName()), capturedProperty.getValue());
+        }
+
+    }
+
+    @DataProvider(name = "updateConfigurations")
+    public Object[][] buildConfigurations() {
+
+        // Only email config is true. Preconditions: all the configs false.
+        Map<String, String> usernameConfig1 = new HashMap<>();
+        usernameConfig1.put(USERNAME_RECOVERY_EMAIL_ENABLE, TRUE_STRING);
+
+        IdentityProviderProperty[] identityProviderProperties1 = getIdentityProviderProperties(
+                false, false, false);
+        Map<String, String> expected1 = getExpectedPropertyValues(true, true, false);
+
+        // Only sms config is true. Preconditions: all the configs false.
+        Map<String, String> usernameConfig2 = new HashMap<>();
+        usernameConfig2.put(USERNAME_RECOVERY_SMS_ENABLE, TRUE_STRING);
+
+        IdentityProviderProperty[] identityProviderProperties2 = getIdentityProviderProperties(
+                false, false, false);
+        Map<String, String> expected2 = getExpectedPropertyValues(true, false, true);
+
+        // Only sms is false. Preconditions: sms and username is true.
+        Map<String, String> usernameConfig3 = new HashMap<>();
+        usernameConfig3.put(USERNAME_RECOVERY_SMS_ENABLE, FALSE_STRING);
+
+        IdentityProviderProperty[] identityProviderProperties3 = getIdentityProviderProperties(
+                true, false, true);
+        Map<String, String> expected3 = getExpectedPropertyValues(false, false, false);
+
+        // Only email is false. Preconditions: email and username is true.
+        Map<String, String> usernameConfig4 = new HashMap<>();
+        usernameConfig4.put(USERNAME_RECOVERY_EMAIL_ENABLE, FALSE_STRING);
+
+        IdentityProviderProperty[] identityProviderProperties4 = getIdentityProviderProperties(
+                true, true, false);
+        Map<String, String> expected4 = getExpectedPropertyValues(false, false, false);
+
+        // Only email is true. Preconditions: sms and username is true.
+        Map<String, String> usernameConfig5 = new HashMap<>();
+        usernameConfig5.put(USERNAME_RECOVERY_EMAIL_ENABLE, TRUE_STRING);
+
+        IdentityProviderProperty[] identityProviderProperties5 = getIdentityProviderProperties(
+                true, false, true);
+        Map<String, String> expected5 = getExpectedPropertyValues(true, true, true);
+
+        // Only sms is true. Preconditions: email and username is true.
+        Map<String, String> usernameConfig6 = new HashMap<>();
+        usernameConfig6.put(USERNAME_RECOVERY_SMS_ENABLE, TRUE_STRING);
+
+        IdentityProviderProperty[] identityProviderProperties6 = getIdentityProviderProperties(
+                true, true, false);
+        Map<String, String> expected6 = getExpectedPropertyValues(true, true, true);
+
+        // Sms config true and email config false. Preconditions: all the configs false.
+        Map<String, String> usernameConfig7 = new HashMap<>();
+        usernameConfig7.put(USERNAME_RECOVERY_SMS_ENABLE, TRUE_STRING);
+        usernameConfig7.put(USERNAME_RECOVERY_EMAIL_ENABLE, FALSE_STRING);
+
+        IdentityProviderProperty[] identityProviderProperties7 = getIdentityProviderProperties(
+                false, false, false);
+        Map<String, String> expected7 = getExpectedPropertyValues(true, false, true);
+
+        // Email config true and sms config false. Preconditions: all the configs false.
+        Map<String, String> usernameConfig8 = new HashMap<>();
+        usernameConfig8.put(USERNAME_RECOVERY_EMAIL_ENABLE, TRUE_STRING);
+        usernameConfig8.put(USERNAME_RECOVERY_SMS_ENABLE, FALSE_STRING);
+
+        IdentityProviderProperty[] identityProviderProperties8 = getIdentityProviderProperties(
+                false, false, false);
+        Map<String, String> expected8 = getExpectedPropertyValues(true, true, false);
+
+        // Sms config true and email config true. Preconditions: all the configs false.
+        Map<String, String> usernameConfig9 = new HashMap<>();
+        usernameConfig9.put(USERNAME_RECOVERY_SMS_ENABLE, TRUE_STRING);
+        usernameConfig9.put(USERNAME_RECOVERY_EMAIL_ENABLE, TRUE_STRING);
+
+        IdentityProviderProperty[] identityProviderProperties9 = getIdentityProviderProperties(
+                false, false, false);
+        Map<String, String> expected9 = getExpectedPropertyValues(true, true, true);
+
+        // Only username config true. Preconditions: all the configs false.
+        Map<String, String> usernameConfig10 = new HashMap<>();
+        usernameConfig10.put(USERNAME_RECOVERY_ENABLE, TRUE_STRING);
+
+        IdentityProviderProperty[] identityProviderProperties10 = getIdentityProviderProperties(
+                false, false, false);
+        Map<String, String> expected10 = getExpectedPropertyValues(true, true, true);
+
+        // Only username config false. Preconditions: all the configs true.
+        Map<String, String> usernameConfig11 = new HashMap<>();
+        usernameConfig11.put(USERNAME_RECOVERY_ENABLE, FALSE_STRING);
+
+        IdentityProviderProperty[] identityProviderProperties11 = getIdentityProviderProperties(
+                true, true, true);
+        Map<String, String> expected11 = getExpectedPropertyValues(false, false, false);
+
+        return new Object[][]{
+                {usernameConfig1, identityProviderProperties1, expected1},
+                {usernameConfig2, identityProviderProperties2, expected2},
+                {usernameConfig3, identityProviderProperties3, expected3},
+                {usernameConfig4, identityProviderProperties4, expected4},
+                {usernameConfig5, identityProviderProperties5, expected5},
+                {usernameConfig6, identityProviderProperties6, expected6},
+                {usernameConfig7, identityProviderProperties7, expected7},
+                {usernameConfig8, identityProviderProperties8, expected8},
+                {usernameConfig9, identityProviderProperties9, expected9},
+                {usernameConfig10, identityProviderProperties10, expected10},
+                {usernameConfig11, identityProviderProperties11, expected11}
+        };
+
+    }
+
+    private IdentityProviderProperty[] getIdentityProviderProperties(boolean usernameEnable,
+                                                                     boolean usernameEmailEnable,
+                                                                     boolean usernameSmsEnable) {
+
+        IdentityProviderProperty identityProviderProperty1 = new IdentityProviderProperty();
+        identityProviderProperty1.setName(USERNAME_RECOVERY_ENABLE);
+        identityProviderProperty1.setValue(usernameEnable ? TRUE_STRING : FALSE_STRING);
+
+        IdentityProviderProperty identityProviderProperty2 = new IdentityProviderProperty();
+        identityProviderProperty2.setName(USERNAME_RECOVERY_SMS_ENABLE);
+        identityProviderProperty2.setValue(usernameSmsEnable ? TRUE_STRING : FALSE_STRING);
+
+        IdentityProviderProperty identityProviderProperty3 = new IdentityProviderProperty();
+        identityProviderProperty3.setName(USERNAME_RECOVERY_EMAIL_ENABLE);
+        identityProviderProperty3.setValue(usernameEmailEnable ? TRUE_STRING : FALSE_STRING);
+
+        return new IdentityProviderProperty[]{
+                identityProviderProperty1,
+                identityProviderProperty2,
+                identityProviderProperty3
+        };
+    }
+
+    private HashMap<String, String> getExpectedPropertyValues(boolean usernameEnable,
+                                                              boolean usernameEmailEnable,
+                                                              boolean usernameSmsEnable) {
+
+        HashMap<String, String> expected = new HashMap<>();
+        expected.put(USERNAME_RECOVERY_ENABLE, usernameEnable ? TRUE_STRING : FALSE_STRING);
+        expected.put(USERNAME_RECOVERY_EMAIL_ENABLE, usernameEmailEnable ? TRUE_STRING : FALSE_STRING);
+        expected.put(USERNAME_RECOVERY_SMS_ENABLE, usernameSmsEnable ? TRUE_STRING : FALSE_STRING);
+
+        return expected;
+    }
+}
diff --git a/components/org.wso2.carbon.identity.governance/src/test/resources/testng.xml b/components/org.wso2.carbon.identity.governance/src/test/resources/testng.xml
index 6a4dc0744..0c10670da 100644
--- a/components/org.wso2.carbon.identity.governance/src/test/resources/testng.xml
+++ b/components/org.wso2.carbon.identity.governance/src/test/resources/testng.xml
@@ -23,8 +23,9 @@
 
     <test name="identity-governance-tests" preserve-order="true" parallel="false">
         <classes>
-            <class name="org.wso2.carbon.identity.governance.listener.IdentityMgtEventListenerTest"></class>
-            <class name="org.wso2.carbon.identity.governance.listener.IdentityStoreEventListenerTest"></class>
+            <class name="org.wso2.carbon.identity.governance.IdentityGovernanceServiceImplTest"/>
+            <class name="org.wso2.carbon.identity.governance.listener.IdentityMgtEventListenerTest"/>
+            <class name="org.wso2.carbon.identity.governance.listener.IdentityStoreEventListenerTest"/>
             <class name="org.wso2.carbon.identity.governance.listener.NotificationTemplateManagerTest"></class>
             <class name="org.wso2.carbon.identity.governance.internal.service.impl.notification.DefaultNotificationChannelManagerTest"/>
         </classes>
diff --git a/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/IdentityRecoveryConstants.java b/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/IdentityRecoveryConstants.java
index 89a02917e..53b3fa0ed 100644
--- a/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/IdentityRecoveryConstants.java
+++ b/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/IdentityRecoveryConstants.java
@@ -615,6 +615,8 @@ public static class ConnectorConfig {
         public static final String FORCE_ADD_PW_RECOVERY_QUESTION = "Recovery.Question.Password.Forced.Enable";
         public static final String FORCE_MIN_NO_QUESTION_ANSWERED = "Recovery.Question.MinQuestionsToAnswer";
         public static final String USERNAME_RECOVERY_ENABLE = "Recovery.Notification.Username.Enable";
+        public static final String USERNAME_RECOVERY_EMAIL_ENABLE = "Recovery.Notification.Username.Email.Enable";
+        public static final String USERNAME_RECOVERY_SMS_ENABLE = "Recovery.Notification.Username.SMS.Enable";
         public static final String USERNAME_RECOVERY_NON_UNIQUE_USERNAME = "Recovery.Notification.Username.NonUniqueUsername";
         public static final String QUESTION_CHALLENGE_SEPARATOR = "Recovery.Question.Password.Separator";
         public static final String QUESTION_MIN_NO_ANSWER = "Recovery.Question.Password.MinAnswers";
diff --git a/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/connector/RecoveryConfigImpl.java b/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/connector/RecoveryConfigImpl.java
index 74ef59ffb..218e43aa0 100644
--- a/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/connector/RecoveryConfigImpl.java
+++ b/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/connector/RecoveryConfigImpl.java
@@ -99,6 +99,10 @@ public Map<String, String> getPropertyNameMapping() {
         nameMapping.put(IdentityRecoveryConstants.ConnectorConfig.QUESTION_MIN_NO_ANSWER, "Number of questions " +
                 "required for password recovery");
         nameMapping.put(IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_ENABLE, "Username recovery");
+        nameMapping.put(IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_EMAIL_ENABLE,
+                "Notification based username recovery via EMAIL");
+        nameMapping.put(IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_SMS_ENABLE,
+                "Notification based username recovery via SMS");
         nameMapping.put(IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_RECAPTCHA_ENABLE,
                 "Enable reCaptcha for username recovery");
         nameMapping.put(IdentityRecoveryConstants.ConnectorConfig.EXPIRY_TIME, "Recovery link expiry time in minutes");
@@ -193,6 +197,8 @@ public String[] getPropertyNames() {
         properties.add(IdentityRecoveryConstants.ConnectorConfig.RECOVERY_QUESTION_PASSWORD_RECAPTCHA_ENABLE);
         properties.add(IdentityRecoveryConstants.ConnectorConfig.RECOVERY_QUESTION_PASSWORD_RECAPTCHA_MAX_FAILED_ATTEMPTS);
         properties.add(IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_ENABLE);
+        properties.add(IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_EMAIL_ENABLE);
+        properties.add(IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_SMS_ENABLE);
         properties.add(IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_RECAPTCHA_ENABLE);
         properties.add(IdentityRecoveryConstants.ConnectorConfig.NOTIFICATION_INTERNALLY_MANAGE);
         properties.add(IdentityRecoveryConstants.ConnectorConfig.NOTIFICATION_SEND_RECOVERY_NOTIFICATION_SUCCESS);
@@ -227,6 +233,8 @@ public Properties getDefaultPropertyValues(String tenantDomain) throws IdentityG
         String enableRecoveryQuestionPasswordReCaptcha = "true";
         String recoveryQuestionPasswordReCaptchaMaxFailedAttempts = "2";
         String enableUsernameRecovery = "false";
+        String enableUsernameRecoveryEmail = "false";
+        String enableUsernameRecoverySMS = "false";
         String enableNotificationInternallyManage = "true";
         String expiryTime = "1440";
         String expiryTimeSMSOTP = "1";
@@ -272,6 +280,10 @@ public Properties getDefaultPropertyValues(String tenantDomain) throws IdentityG
                 ConnectorConfig.RECOVERY_QUESTION_PASSWORD_RECAPTCHA_MAX_FAILED_ATTEMPTS);
         String usernameRecovery = IdentityUtil.getProperty(
                 IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_ENABLE);
+        String usernameRecoveryEmail = IdentityUtil.getProperty(
+                IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_EMAIL_ENABLE);
+        String usernameRecoverySMS = IdentityUtil.getProperty(
+                IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_SMS_ENABLE);
         String notificationInternallyManged = IdentityUtil.getProperty(
                 IdentityRecoveryConstants.ConnectorConfig.NOTIFICATION_INTERNALLY_MANAGE);
         String expiryTimeProperty = IdentityUtil.getProperty(IdentityRecoveryConstants.ConnectorConfig.EXPIRY_TIME);
@@ -351,6 +363,14 @@ public Properties getDefaultPropertyValues(String tenantDomain) throws IdentityG
         }
         if (StringUtils.isNotEmpty(usernameRecovery)) {
             enableUsernameRecovery = usernameRecovery;
+            // Setting the username recovery value to keep backward compatibility.
+            enableUsernameRecoveryEmail = usernameRecovery;
+        }
+        if (StringUtils.isNotEmpty(usernameRecoveryEmail)){
+            enableUsernameRecoveryEmail = usernameRecoveryEmail;
+        }
+        if (StringUtils.isNotEmpty(usernameRecoverySMS)) {
+            enableUsernameRecoverySMS = usernameRecoverySMS;
         }
         if (StringUtils.isNotEmpty(expiryTimeProperty)) {
             expiryTime = expiryTimeProperty;
@@ -433,6 +453,10 @@ public Properties getDefaultPropertyValues(String tenantDomain) throws IdentityG
                 recoveryQuestionPasswordReCaptchaMaxFailedAttempts);
         defaultProperties.put(IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_ENABLE,
                 enableUsernameRecovery);
+        defaultProperties.put(IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_EMAIL_ENABLE,
+                enableUsernameRecoveryEmail);
+        defaultProperties.put(IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_SMS_ENABLE,
+                enableUsernameRecoverySMS);
         defaultProperties.put(IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_RECAPTCHA_ENABLE,
                 enableUsernameRecoveryReCaptcha);
         defaultProperties.put(IdentityRecoveryConstants.ConnectorConfig.NOTIFICATION_INTERNALLY_MANAGE,
@@ -518,6 +542,12 @@ public Map<String, Property> getMetaData() {
         meta.put(IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_ENABLE,
                 getPropertyObject(IdentityMgtConstants.DataTypes.BOOLEAN.getValue()));
 
+        meta.put(IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_EMAIL_ENABLE,
+                getPropertyObject(IdentityMgtConstants.DataTypes.BOOLEAN.getValue()));
+
+        meta.put(IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_SMS_ENABLE,
+                getPropertyObject(IdentityMgtConstants.DataTypes.BOOLEAN.getValue()));
+
         meta.put(IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_RECAPTCHA_ENABLE,
                 getPropertyObject(IdentityMgtConstants.DataTypes.BOOLEAN.getValue()));
 
diff --git a/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/internal/service/impl/UserAccountRecoveryManager.java b/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/internal/service/impl/UserAccountRecoveryManager.java
index 79f04f274..e9c5e32d8 100644
--- a/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/internal/service/impl/UserAccountRecoveryManager.java
+++ b/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/internal/service/impl/UserAccountRecoveryManager.java
@@ -23,6 +23,7 @@
 import org.apache.commons.logging.LogFactory;
 
 import org.wso2.carbon.identity.application.common.model.User;
+import org.wso2.carbon.identity.base.IdentityException;
 import org.wso2.carbon.identity.claim.metadata.mgt.exception.ClaimMetadataException;
 import org.wso2.carbon.identity.core.util.IdentityTenantUtil;
 import org.wso2.carbon.identity.core.util.IdentityUtil;
@@ -108,6 +109,107 @@ public static UserAccountRecoveryManager getInstance() {
         return instance;
     }
 
+    /**
+     * Initiate the username recovery flow for the user with matching claims when non-unique user config enabled.
+     *
+     * @param claims           User claims
+     * @param tenantDomain     Tenant domain
+     * @param properties       Meta properties
+     * @return RecoveryChannelInfoDTO object.
+     */
+    public RecoveryChannelInfoDTO retrieveUsersRecoveryInformationForUsername(Map<String, String> claims,
+                                                                              String tenantDomain,
+                                                                              Map<String, String> properties)
+            throws IdentityRecoveryException {
+
+        RecoveryScenarios recoveryScenario = RecoveryScenarios.USERNAME_RECOVERY;
+        // Retrieve the user who matches the given set of claims.
+        ArrayList<org.wso2.carbon.user.core.common.User> resultedUserList = getUserListByClaims(claims, tenantDomain);
+
+        if (!resultedUserList.isEmpty()) {
+            StringBuilder usernameCombined = new StringBuilder();
+            // Get the notification management mechanism.
+            List<NotificationChannel> notificationChannels;
+            boolean isNotificationsInternallyManaged = Utils.isNotificationsInternallyManaged(tenantDomain, properties);
+            String recoveryFlowId = null;
+            String recoveryCode = null;
+            String notificationChannelList = null;
+            String username = null;
+            NotificationChannelDTO[] notificationChannelDTOS = null;
+
+            for (org.wso2.carbon.user.core.common.User resultedUser : resultedUserList) {
+                username = resultedUser.getUsername();
+                User user = Utils.buildUser(username, tenantDomain);
+
+                try {
+                    // If the account is locked or disabled, do not let the user, recover the account.
+                    checkAccountLockedStatus(user);
+
+                } catch (IdentityException e) {
+                    if (log.isDebugEnabled()) {
+                        log.debug(username + " is locked.");
+                    }
+                    continue;
+                }
+
+                /* If the notification is internally managed, then notification channels available for the user needs to
+                be retrieved. If external notifications are enabled, external channel list should be returned.*/
+                if (isNotificationsInternallyManaged) {
+                    notificationChannels = getInternalNotificationChannelList(username, tenantDomain,
+                            recoveryScenario);
+                } else {
+                    notificationChannels = getExternalNotificationChannelList();
+                }
+
+                // Validate whether the user account is eligible for account recovery.
+                checkUserValidityForAccountRecovery(user, recoveryScenario, notificationChannels, properties);
+                // This flow will be initiated only if the user has any verified channels.
+                notificationChannelDTOS = getNotificationChannelsResponseDTOList(
+                        tenantDomain, notificationChannels);
+                UserRecoveryDataStore userRecoveryDataStore = JDBCRecoveryDataStore.getInstance();
+                // Get the existing RESEND_CONFIRMATION_CODE details if there is any.
+                UserRecoveryData recoveryDataDO = userRecoveryDataStore.loadWithoutCodeExpiryValidation(
+                        user, recoveryScenario, RecoverySteps.RESEND_CONFIRMATION_CODE);
+
+                notificationChannelList = getNotificationChannelListForRecovery(notificationChannels);
+                recoveryCode = UUID.randomUUID().toString();
+                recoveryFlowId = UUID.randomUUID().toString();
+
+                if (Utils.reIssueExistingConfirmationCode(recoveryDataDO,
+                        NotificationChannels.EMAIL_CHANNEL.getChannelType())) {
+                /* Update the existing RESEND_CONFIRMATION_CODE details with new code details without changing the
+                   time created of the RESEND_CONFIRMATION_CODE. */
+                    userRecoveryDataStore.invalidateWithoutChangeTimeCreated(recoveryDataDO.getSecret(), recoveryCode,
+                            RecoverySteps.SEND_RECOVERY_INFORMATION, notificationChannelList);
+                } else {
+                    if (usernameCombined.length() > 0) {
+                        usernameCombined.append(",");
+                    }
+                    usernameCombined.append(username);
+                }
+            }
+            if (StringUtils.isBlank(usernameCombined.toString())) {
+                if (log.isDebugEnabled()) {
+                    log.debug("No valid user found for the given claims");
+                }
+                throw Utils.handleClientException(IdentityRecoveryConstants.ErrorMessages.ERROR_CODE_NO_USER_FOUND,
+                        null);
+            }
+            addRecoveryDataObject(usernameCombined.toString(), tenantDomain, recoveryFlowId, recoveryCode,
+                    recoveryScenario,
+                    notificationChannelList);
+
+            return buildUserRecoveryInformationResponseDTO(username, recoveryFlowId, recoveryCode,
+                    notificationChannelDTOS);
+
+        } else {
+            if (log.isDebugEnabled()) {
+                log.debug("No valid user found for the given claims");
+            }
+            throw Utils.handleClientException(IdentityRecoveryConstants.ErrorMessages.ERROR_CODE_NO_USER_FOUND, null);
+        }
+    }
+
     /**
      * Initiate the recovery flow for the user with matching claims.
      *
diff --git a/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/internal/service/impl/username/UsernameRecoveryManagerImpl.java b/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/internal/service/impl/username/UsernameRecoveryManagerImpl.java
index f661daec6..742155fe9 100644
--- a/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/internal/service/impl/username/UsernameRecoveryManagerImpl.java
+++ b/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/internal/service/impl/username/UsernameRecoveryManagerImpl.java
@@ -37,6 +37,8 @@
 import org.wso2.carbon.identity.recovery.IdentityRecoveryServerException;
 import org.wso2.carbon.identity.recovery.RecoveryScenarios;
 import org.wso2.carbon.identity.recovery.RecoverySteps;
+import org.wso2.carbon.identity.recovery.dto.NotificationChannelDTO;
+import org.wso2.carbon.identity.recovery.dto.RecoveryChannelInfoDTO;
 import org.wso2.carbon.identity.recovery.dto.RecoveryInformationDTO;
 import org.wso2.carbon.identity.recovery.dto.UsernameRecoverDTO;
 import org.wso2.carbon.identity.recovery.internal.IdentityRecoveryServiceDataHolder;
@@ -55,6 +57,7 @@
 import java.net.URLDecoder;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.AUDIT_FAILED;
@@ -134,9 +137,35 @@ public RecoveryInformationDTO initiate(Map<String, String> claims, String tenant
         Map<String, String> metaProperties = new HashMap<>();
         metaProperties.put(IdentityRecoveryConstants.MANAGE_NOTIFICATIONS_INTERNALLY_PROPERTY_KEY,
                 Boolean.toString(manageNotificationsInternally));
-        recoveryInformationDTO.setRecoveryChannelInfoDTO(userAccountRecoveryManager
-                .retrieveUserRecoveryInformation(claims, tenantDomain, RecoveryScenarios.USERNAME_RECOVERY,
-                        metaProperties));
+
+        boolean nonUniqueUsernameEnabled = Boolean.parseBoolean(IdentityUtil.getProperty(
+                IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_NON_UNIQUE_USERNAME));
+
+        RecoveryChannelInfoDTO recoveryChannelInfoDTO;
+        if (nonUniqueUsernameEnabled) {
+            recoveryChannelInfoDTO = userAccountRecoveryManager
+                    .retrieveUsersRecoveryInformationForUsername(claims, tenantDomain, metaProperties);
+        } else {
+            recoveryChannelInfoDTO = userAccountRecoveryManager
+                    .retrieveUserRecoveryInformation(claims, tenantDomain, RecoveryScenarios.USERNAME_RECOVERY,
+                            metaProperties);
+        }
+
+        // Filtering the notification channel list.
+        List<NotificationChannelDTO> enabledNotificationChannelDTOs = new ArrayList<>();
+        for (NotificationChannelDTO notificationChannelDTO : recoveryChannelInfoDTO.getNotificationChannelDTOs()) {
+            if (isRecoveryChannelEnabled(notificationChannelDTO.getType(), tenantDomain)) {
+                enabledNotificationChannelDTOs.add(notificationChannelDTO);
+            }
+        }
+        recoveryChannelInfoDTO.setNotificationChannelDTOs(
+                enabledNotificationChannelDTOs.toArray(new NotificationChannelDTO[0]));
+        String username = recoveryChannelInfoDTO.getUsername();
+        String recoveryFlowId = recoveryChannelInfoDTO.getRecoveryFlowId();
+        recoveryInformationDTO.setUsername(username);
+        recoveryInformationDTO.setRecoveryFlowId(recoveryFlowId);
+        // Do not add recovery channel information if Notification based recovery is not enabled.
+        recoveryInformationDTO.setRecoveryChannelInfoDTO(recoveryChannelInfoDTO);
         return recoveryInformationDTO;
     }
 
@@ -263,9 +292,15 @@ private UsernameRecoverDTO buildUserNameRecoveryResponseDTO(User user, String no
 
             // If notifications are externally managed, username needs to be sent with the request.
             // Build username for external notification.
-            String username =
-                    String.format(qualifiedUsernameRegexPattern, user.getUserName(), user.getTenantDomain());
-            usernameRecoverDTO.setUsername(username);
+            StringBuilder usernameCombined = new StringBuilder();
+            String[] usernames = user.getUserName().split(",");
+            for (String username : usernames) {
+                if(usernameCombined.length() > 0) {
+                    usernameCombined.append(",");
+                }
+                usernameCombined.append(String.format(qualifiedUsernameRegexPattern, username, user.getTenantDomain()));
+            }
+            usernameRecoverDTO.setUsername(usernameCombined.toString());
         } else {
             usernameRecoverDTO.setCode(
                     IdentityRecoveryConstants.SuccessEvents.SUCCESS_STATUS_CODE_USERNAME_INTERNALLY_NOTIFIED.getCode());
@@ -313,27 +348,36 @@ private void triggerNotification(User user, String notificationChannel, String e
                                      Map<String, String> metaProperties)
             throws IdentityRecoveryException {
 
-        HashMap<String, Object> properties = new HashMap<>();
-        properties.put(IdentityEventConstants.EventProperty.USER_NAME, user.getUserName());
-        properties.put(IdentityEventConstants.EventProperty.TENANT_DOMAIN, user.getTenantDomain());
-        properties.put(IdentityEventConstants.EventProperty.USER_STORE_DOMAIN, user.getUserStoreDomain());
-        properties.put(IdentityEventConstants.EventProperty.NOTIFICATION_CHANNEL, notificationChannel);
-        if (metaProperties != null) {
-            for (String key : metaProperties.keySet()) {
-                String value = metaProperties.get(key);
-                if (StringUtils.isNotBlank(key) && StringUtils.isNotBlank(value)) {
-                    properties.put(key, value);
+        if (!isRecoveryChannelEnabled(notificationChannel, user.getTenantDomain())) {
+            throw Utils.handleClientException(
+                    IdentityRecoveryConstants.ErrorMessages.ERROR_CODE_INVALID_CHANNEL_ID, null);
+        }
+
+        String combinedUsernames = user.getUserName();
+        String[] usernames = combinedUsernames.split(",");
+        for (String username : usernames) {
+            HashMap<String, Object> properties = new HashMap<>();
+            properties.put(IdentityEventConstants.EventProperty.USER_NAME, username);
+            properties.put(IdentityEventConstants.EventProperty.TENANT_DOMAIN, user.getTenantDomain());
+            properties.put(IdentityEventConstants.EventProperty.USER_STORE_DOMAIN, user.getUserStoreDomain());
+            properties.put(IdentityEventConstants.EventProperty.NOTIFICATION_CHANNEL, notificationChannel);
+            if (metaProperties != null) {
+                for (String key : metaProperties.keySet()) {
+                    String value = metaProperties.get(key);
+                    if (StringUtils.isNotBlank(key) && StringUtils.isNotBlank(value)) {
+                        properties.put(key, value);
+                    }
                 }
             }
-        }
-        properties.put(IdentityRecoveryConstants.TEMPLATE_TYPE,
-                IdentityRecoveryConstants.NOTIFICATION_ACCOUNT_ID_RECOVERY);
-        Event identityMgtEvent = new Event(eventName, properties);
-        try {
-            IdentityRecoveryServiceDataHolder.getInstance().getIdentityEventService().handleEvent(identityMgtEvent);
-        } catch (IdentityEventException e) {
-            throw Utils.handleServerException(IdentityRecoveryConstants.ErrorMessages.ERROR_CODE_TRIGGER_NOTIFICATION,
-                    user.getUserName(), e);
+            properties.put(IdentityRecoveryConstants.TEMPLATE_TYPE,
+                    IdentityRecoveryConstants.NOTIFICATION_ACCOUNT_ID_RECOVERY);
+            Event identityMgtEvent = new Event(eventName, properties);
+            try {
+                IdentityRecoveryServiceDataHolder.getInstance().getIdentityEventService().handleEvent(identityMgtEvent);
+            } catch (IdentityEventException e) {
+                throw Utils.handleServerException(IdentityRecoveryConstants.ErrorMessages.ERROR_CODE_TRIGGER_NOTIFICATION,
+                        user.getUserName(), e);
+            }
         }
     }
 
@@ -467,4 +511,47 @@ private void auditUserNameRecovery(String action, Map<String, String> claims, St
         }
         Utils.createAuditMessage(action, target, dataObject, result);
     }
+
+    private boolean isRecoveryChannelEnabled(String notificationChannelType, String tenantDomain)
+            throws IdentityRecoveryServerException {
+
+        if (NotificationChannels.EMAIL_CHANNEL.getChannelType().equals(notificationChannelType)) {
+            return isEmailBasedRecoveryEnabled(tenantDomain);
+        } else if (NotificationChannels.SMS_CHANNEL.getChannelType().equals(notificationChannelType)) {
+            return isSMSBasedRecoveryEnabled(tenantDomain);
+        }
+        return false;
+    }
+
+    private boolean isEmailBasedRecoveryEnabled(String tenantDomain) throws IdentityRecoveryServerException {
+
+        try {
+            return Boolean.parseBoolean(
+                    Utils.getRecoveryConfigs(
+                            IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_EMAIL_ENABLE,
+                            tenantDomain));
+        } catch (IdentityRecoveryServerException e) {
+            // Prepend scenario to the thrown exception.
+            String errorCode = Utils
+                    .prependOperationScenarioToErrorCode(IdentityRecoveryConstants.USER_NAME_RECOVERY,
+                            e.getErrorCode());
+            throw Utils.handleServerException(errorCode, e.getMessage(), null);
+        }
+    }
+
+    private boolean isSMSBasedRecoveryEnabled(String tenantDomain) throws IdentityRecoveryServerException {
+
+        try {
+            return Boolean.parseBoolean(
+                    Utils.getRecoveryConfigs(
+                            IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_SMS_ENABLE,
+                            tenantDomain));
+        } catch (IdentityRecoveryServerException e) {
+            // Prepend scenario to the thrown exception.
+            String errorCode = Utils
+                    .prependOperationScenarioToErrorCode(IdentityRecoveryConstants.USER_NAME_RECOVERY,
+                            e.getErrorCode());
+            throw Utils.handleServerException(errorCode, e.getMessage(), null);
+        }
+    }
 }
diff --git a/components/org.wso2.carbon.identity.recovery/src/test/java/org/wso2/carbon/identity/recovery/connector/RecoveryConfigImplTest.java b/components/org.wso2.carbon.identity.recovery/src/test/java/org/wso2/carbon/identity/recovery/connector/RecoveryConfigImplTest.java
index beaf4d247..8975a13b8 100644
--- a/components/org.wso2.carbon.identity.recovery/src/test/java/org/wso2/carbon/identity/recovery/connector/RecoveryConfigImplTest.java
+++ b/components/org.wso2.carbon.identity.recovery/src/test/java/org/wso2/carbon/identity/recovery/connector/RecoveryConfigImplTest.java
@@ -18,8 +18,13 @@
 package org.wso2.carbon.identity.recovery.connector;
 
 import org.apache.commons.lang.StringUtils;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
 import org.testng.annotations.BeforeTest;
+import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
+import org.wso2.carbon.identity.application.common.model.Property;
+import org.wso2.carbon.identity.core.util.IdentityUtil;
 import org.wso2.carbon.identity.governance.IdentityGovernanceException;
 import org.wso2.carbon.identity.governance.IdentityMgtConstants;
 import org.wso2.carbon.identity.recovery.IdentityRecoveryConstants;
@@ -32,6 +37,7 @@
 
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNull;
+import static org.wso2.carbon.identity.governance.IdentityGovernanceUtil.getPropertyObject;
 
 /**
  * This class does unit test coverage for RecoveryConfigImpl class.
@@ -105,6 +111,10 @@ public void testGetPropertyNameMapping() {
         nameMappingExpected.put(IdentityRecoveryConstants.ConnectorConfig.QUESTION_MIN_NO_ANSWER, "Number of " +
                 "questions required for password recovery");
         nameMappingExpected.put(IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_ENABLE, "Username recovery");
+        nameMappingExpected.put(IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_EMAIL_ENABLE,
+                "Notification based username recovery via EMAIL");
+        nameMappingExpected.put(IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_SMS_ENABLE,
+                "Notification based username recovery via SMS");
         nameMappingExpected.put(IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_RECAPTCHA_ENABLE,
                 "Enable reCaptcha for username recovery");
         nameMappingExpected.put(IdentityRecoveryConstants.ConnectorConfig.EXPIRY_TIME,
@@ -206,6 +216,8 @@ public void testGetPropertyNames() {
         propertiesExpected.add(IdentityRecoveryConstants.ConnectorConfig.RECOVERY_QUESTION_PASSWORD_RECAPTCHA_ENABLE);
         propertiesExpected.add(IdentityRecoveryConstants.ConnectorConfig.RECOVERY_QUESTION_PASSWORD_RECAPTCHA_MAX_FAILED_ATTEMPTS);
         propertiesExpected.add(IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_ENABLE);
+        propertiesExpected.add(IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_EMAIL_ENABLE);
+        propertiesExpected.add(IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_SMS_ENABLE);
         propertiesExpected.add(IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_RECAPTCHA_ENABLE);
         propertiesExpected.add(IdentityRecoveryConstants.ConnectorConfig.NOTIFICATION_INTERNALLY_MANAGE);
         propertiesExpected.add(IdentityRecoveryConstants.ConnectorConfig.NOTIFICATION_SEND_RECOVERY_NOTIFICATION_SUCCESS);
@@ -241,6 +253,8 @@ public void testGetDefaultPropertyValues() throws IdentityGovernanceException {
         String testEnableRecoveryQuestionPasswordReCaptcha = "true";
         String testRecoveryQuestionPasswordReCaptchaMaxFailedAttempts = "2";
         String testEnableUsernameRecovery = "false";
+        String testEnableUsernameRecoveryEmail = "false";
+        String testEnableUsernameRecoverySMS = "false";
         String testEnableNotificationInternallyManage = "true";
         String testExpiryTime = "1440";
         String testExpiryTimeSMSOTP = "1";
@@ -286,6 +300,10 @@ public void testGetDefaultPropertyValues() throws IdentityGovernanceException {
                 testRecoveryQuestionPasswordReCaptchaMaxFailedAttempts);
         defaultPropertiesExpected.put(IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_ENABLE,
                 testEnableUsernameRecovery);
+        defaultPropertiesExpected.put(IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_EMAIL_ENABLE,
+                testEnableUsernameRecoveryEmail);
+        defaultPropertiesExpected.put(IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_SMS_ENABLE,
+                testEnableUsernameRecoverySMS);
         defaultPropertiesExpected.put(IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_RECAPTCHA_ENABLE,
                 enableUsernameRecoveryReCaptcha);
         defaultPropertiesExpected.put(IdentityRecoveryConstants.ConnectorConfig.NOTIFICATION_INTERNALLY_MANAGE,
@@ -327,6 +345,199 @@ public void testGetDefaultPropertyValues() throws IdentityGovernanceException {
         assertEquals(defaultProperties, defaultPropertiesExpected, "Maps are not equal");
     }
 
+    @Test(dataProvider = "defaultPropertyNames")
+    public void testGetDefaultPropertyValuesConditional(String property) throws IdentityGovernanceException{
+
+        String tenantDomain = "admin";
+        String testPropertyValue = "testValue";
+        try(MockedStatic<IdentityUtil> identityUtilMockedStatic = Mockito.mockStatic(IdentityUtil.class)) {
+            identityUtilMockedStatic.when(() -> IdentityUtil.getProperty(property)).thenReturn(testPropertyValue);
+
+            Properties properties = recoveryConfigImpl.getDefaultPropertyValues(tenantDomain);
+            assertEquals(testPropertyValue, properties.getProperty(property));
+        }
+    }
+
+    @DataProvider(name="defaultPropertyNames")
+    public Object[][] buildPropertyNameList(){
+
+        return new Object[][] {
+                {IdentityRecoveryConstants.ConnectorConfig.NOTIFICATION_BASED_PW_RECOVERY},
+                {IdentityRecoveryConstants.ConnectorConfig.PASSWORD_RECOVERY_SEND_OTP_IN_EMAIL},
+                {IdentityRecoveryConstants.ConnectorConfig.PASSWORD_RECOVERY_USE_UPPERCASE_CHARACTERS_IN_OTP},
+                {IdentityRecoveryConstants.ConnectorConfig.PASSWORD_RECOVERY_USE_LOWERCASE_CHARACTERS_IN_OTP},
+                {IdentityRecoveryConstants.ConnectorConfig.PASSWORD_RECOVERY_USE_NUMBERS_IN_OTP},
+                {IdentityRecoveryConstants.ConnectorConfig.PASSWORD_RECOVERY_OTP_LENGTH},
+                {IdentityRecoveryConstants.ConnectorConfig.PASSWORD_RECOVERY_RECAPTCHA_ENABLE},
+                {IdentityRecoveryConstants.ConnectorConfig.QUESTION_BASED_PW_RECOVERY},
+                {IdentityRecoveryConstants.ConnectorConfig.QUESTION_MIN_NO_ANSWER},
+                {IdentityRecoveryConstants.ConnectorConfig.CHALLENGE_QUESTION_ANSWER_REGEX},
+                {IdentityRecoveryConstants.ConnectorConfig.ENFORCE_CHALLENGE_QUESTION_ANSWER_UNIQUENESS},
+                {IdentityRecoveryConstants.ConnectorConfig.RECOVERY_QUESTION_PASSWORD_RECAPTCHA_ENABLE},
+                {IdentityRecoveryConstants.ConnectorConfig.RECOVERY_QUESTION_PASSWORD_RECAPTCHA_MAX_FAILED_ATTEMPTS},
+                {IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_ENABLE},
+                {IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_EMAIL_ENABLE},
+                {IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_SMS_ENABLE},
+                {IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_RECAPTCHA_ENABLE},
+                {IdentityRecoveryConstants.ConnectorConfig.NOTIFICATION_INTERNALLY_MANAGE},
+                {IdentityRecoveryConstants.ConnectorConfig.EXPIRY_TIME},
+                {IdentityRecoveryConstants.ConnectorConfig.PASSWORD_RECOVERY_SMS_OTP_EXPIRY_TIME},
+                {IdentityRecoveryConstants.ConnectorConfig.PASSWORD_RECOVERY_SMS_OTP_REGEX},
+                {IdentityRecoveryConstants.ConnectorConfig.NOTIFICATION_SEND_RECOVERY_NOTIFICATION_SUCCESS},
+                {IdentityRecoveryConstants.ConnectorConfig.NOTIFICATION_SEND_RECOVERY_SECURITY_START},
+                {IdentityRecoveryConstants.ConnectorConfig.FORCE_ADD_PW_RECOVERY_QUESTION},
+                {IdentityRecoveryConstants.ConnectorConfig.FORCE_MIN_NO_QUESTION_ANSWERED},
+                {IdentityRecoveryConstants.ConnectorConfig.ENABLE_AUTO_LGOIN_AFTER_PASSWORD_RESET},
+                {IdentityRecoveryConstants.ConnectorConfig.RECOVERY_NOTIFICATION_PASSWORD_MAX_FAILED_ATTEMPTS},
+                {IdentityRecoveryConstants.ConnectorConfig.RECOVERY_NOTIFICATION_PASSWORD_MAX_RESEND_ATTEMPTS},
+                {IdentityRecoveryConstants.ConnectorConfig.PASSWORD_RECOVERY_EMAIL_LINK_ENABLE},
+                {IdentityRecoveryConstants.ConnectorConfig.PASSWORD_RECOVERY_SMS_OTP_ENABLE}
+        };
+    }
+
+    @Test
+    public void testGetMetaData() {
+
+        Map<String, Property> metaDataExpected = new HashMap<>();
+
+        Property testNotificationBasedPasswordRecovery =
+                getPropertyObject(IdentityMgtConstants.DataTypes.BOOLEAN.getValue());
+        Property testPasswordRecoverySendOtpInEmail =
+                getPropertyObject(IdentityMgtConstants.DataTypes.BOOLEAN.getValue());
+        Property testPasswordRecoveryUseUppercaseCharactersInOtp =
+                getPropertyObject(IdentityMgtConstants.DataTypes.BOOLEAN.getValue());
+        Property testPasswordRecoveryUseLowercaseCharactersInOtp =
+                getPropertyObject(IdentityMgtConstants.DataTypes.BOOLEAN.getValue());
+        Property testPasswordRecoveryUseNumbersInOtp =
+                getPropertyObject(IdentityMgtConstants.DataTypes.BOOLEAN.getValue());
+        Property testPasswordRecoveryOtpLength =
+                getPropertyObject(IdentityMgtConstants.DataTypes.STRING.getValue());
+        Property testPasswordRecoveryRecaptchaEnable =
+                getPropertyObject(IdentityMgtConstants.DataTypes.BOOLEAN.getValue());
+        Property testQuestionBasedPwRecovery =
+                getPropertyObject(IdentityMgtConstants.DataTypes.BOOLEAN.getValue());
+        Property testQuestionMinNoAnswer =
+                getPropertyObject(IdentityMgtConstants.DataTypes.INTEGER.getValue());
+        Property testEnforceChallengeQuestionAnswerUniqueness =
+                getPropertyObject(IdentityMgtConstants.DataTypes.BOOLEAN.getValue());
+        Property testRecoveryQuestionPasswordRecaptchaEnable =
+                getPropertyObject(IdentityMgtConstants.DataTypes.BOOLEAN.getValue());
+        Property testRecoveryQuestionPasswordRecaptchaMaxFailedAttempts =
+                getPropertyObject(IdentityMgtConstants.DataTypes.INTEGER.getValue());
+        Property testUsernameRecoveryEnable =
+                getPropertyObject(IdentityMgtConstants.DataTypes.BOOLEAN.getValue());
+        Property testUsernameRecoveryEmailEnable =
+                getPropertyObject(IdentityMgtConstants.DataTypes.BOOLEAN.getValue());
+        Property testUsernameRecoverySmsEnable =
+                getPropertyObject(IdentityMgtConstants.DataTypes.BOOLEAN.getValue());
+        Property testUsernameRecoveryRecaptchaEnable =
+                getPropertyObject(IdentityMgtConstants.DataTypes.BOOLEAN.getValue());
+        Property testNotificationInternallyManage =
+                getPropertyObject(IdentityMgtConstants.DataTypes.BOOLEAN.getValue());
+        Property testExpiryTime =
+                getPropertyObject(IdentityMgtConstants.DataTypes.INTEGER.getValue());
+        Property testPasswordRecoverySmsOtpExpiryTime =
+                getPropertyObject(IdentityMgtConstants.DataTypes.INTEGER.getValue());
+        Property testNotificationSendRecoveryNotificationSuccess =
+                getPropertyObject(IdentityMgtConstants.DataTypes.BOOLEAN.getValue());
+        Property testNotificationSendRecoverySecurityStart =
+                getPropertyObject(IdentityMgtConstants.DataTypes.BOOLEAN.getValue());
+        Property testForceAddPwRecoveryQuestion =
+                getPropertyObject(IdentityMgtConstants.DataTypes.BOOLEAN.getValue());
+        Property testForceMinNoQuestionAnswered =
+                getPropertyObject(IdentityMgtConstants.DataTypes.INTEGER.getValue());
+        Property testEnableAutoLoginAfterPasswordReset =
+                getPropertyObject(IdentityMgtConstants.DataTypes.BOOLEAN.getValue());
+        Property testChallengeQuestionAnswerRegex =
+                getPropertyObject(IdentityMgtConstants.DataTypes.STRING.getValue());
+        Property testRecoveryCallbackRegex =
+                getPropertyObject(IdentityMgtConstants.DataTypes.STRING.getValue());
+        Property testRecoveryNotificationPasswordMaxFailedAttempts =
+                getPropertyObject(IdentityMgtConstants.DataTypes.INTEGER.getValue());
+        Property testRecoveryNotificationPasswordMaxResendAttempts =
+                getPropertyObject(IdentityMgtConstants.DataTypes.INTEGER.getValue());
+        Property testPasswordRecoveryEmailLinkEnable =
+                getPropertyObject(IdentityMgtConstants.DataTypes.BOOLEAN.getValue());
+        Property testPasswordRecoverySmsOtpEnable =
+                getPropertyObject(IdentityMgtConstants.DataTypes.BOOLEAN.getValue());
+        Property testPasswordRecoverySmsOtpRegex =
+                getPropertyObject(IdentityMgtConstants.DataTypes.STRING.getValue());
+
+        // Adding properties to the expected metadata map.
+        metaDataExpected.put(IdentityRecoveryConstants.ConnectorConfig.NOTIFICATION_BASED_PW_RECOVERY,
+                testNotificationBasedPasswordRecovery);
+        metaDataExpected.put(IdentityRecoveryConstants.ConnectorConfig.PASSWORD_RECOVERY_SEND_OTP_IN_EMAIL,
+                testPasswordRecoverySendOtpInEmail);
+        metaDataExpected.put(
+                IdentityRecoveryConstants.ConnectorConfig.PASSWORD_RECOVERY_USE_UPPERCASE_CHARACTERS_IN_OTP,
+                testPasswordRecoveryUseUppercaseCharactersInOtp);
+        metaDataExpected.put(
+                IdentityRecoveryConstants.ConnectorConfig.PASSWORD_RECOVERY_USE_LOWERCASE_CHARACTERS_IN_OTP,
+                testPasswordRecoveryUseLowercaseCharactersInOtp);
+        metaDataExpected.put(IdentityRecoveryConstants.ConnectorConfig.PASSWORD_RECOVERY_USE_NUMBERS_IN_OTP,
+                testPasswordRecoveryUseNumbersInOtp);
+        metaDataExpected.put(IdentityRecoveryConstants.ConnectorConfig.PASSWORD_RECOVERY_OTP_LENGTH,
+                testPasswordRecoveryOtpLength);
+        metaDataExpected.put(IdentityRecoveryConstants.ConnectorConfig.PASSWORD_RECOVERY_RECAPTCHA_ENABLE,
+                testPasswordRecoveryRecaptchaEnable);
+        metaDataExpected.put(IdentityRecoveryConstants.ConnectorConfig.QUESTION_BASED_PW_RECOVERY,
+                testQuestionBasedPwRecovery);
+        metaDataExpected.put(IdentityRecoveryConstants.ConnectorConfig.QUESTION_MIN_NO_ANSWER, testQuestionMinNoAnswer);
+        metaDataExpected.put(IdentityRecoveryConstants.ConnectorConfig.ENFORCE_CHALLENGE_QUESTION_ANSWER_UNIQUENESS,
+                testEnforceChallengeQuestionAnswerUniqueness);
+        metaDataExpected.put(IdentityRecoveryConstants.ConnectorConfig.RECOVERY_QUESTION_PASSWORD_RECAPTCHA_ENABLE,
+                testRecoveryQuestionPasswordRecaptchaEnable);
+        metaDataExpected.put(
+                IdentityRecoveryConstants.ConnectorConfig.RECOVERY_QUESTION_PASSWORD_RECAPTCHA_MAX_FAILED_ATTEMPTS,
+                testRecoveryQuestionPasswordRecaptchaMaxFailedAttempts);
+        metaDataExpected.put(IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_ENABLE,
+                testUsernameRecoveryEnable);
+        metaDataExpected.put(IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_EMAIL_ENABLE,
+                testUsernameRecoveryEmailEnable);
+        metaDataExpected.put(IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_SMS_ENABLE,
+                testUsernameRecoverySmsEnable);
+        metaDataExpected.put(IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_RECAPTCHA_ENABLE,
+                testUsernameRecoveryRecaptchaEnable);
+        metaDataExpected.put(IdentityRecoveryConstants.ConnectorConfig.NOTIFICATION_INTERNALLY_MANAGE,
+                testNotificationInternallyManage);
+        metaDataExpected.put(IdentityRecoveryConstants.ConnectorConfig.EXPIRY_TIME, testExpiryTime);
+        metaDataExpected.put(IdentityRecoveryConstants.ConnectorConfig.PASSWORD_RECOVERY_SMS_OTP_EXPIRY_TIME,
+                testPasswordRecoverySmsOtpExpiryTime);
+        metaDataExpected.put(IdentityRecoveryConstants.ConnectorConfig.NOTIFICATION_SEND_RECOVERY_NOTIFICATION_SUCCESS,
+                testNotificationSendRecoveryNotificationSuccess);
+        metaDataExpected.put(IdentityRecoveryConstants.ConnectorConfig.NOTIFICATION_SEND_RECOVERY_SECURITY_START,
+                testNotificationSendRecoverySecurityStart);
+        metaDataExpected.put(IdentityRecoveryConstants.ConnectorConfig.FORCE_ADD_PW_RECOVERY_QUESTION,
+                testForceAddPwRecoveryQuestion);
+        metaDataExpected.put(IdentityRecoveryConstants.ConnectorConfig.FORCE_MIN_NO_QUESTION_ANSWERED,
+                testForceMinNoQuestionAnswered);
+        metaDataExpected.put(IdentityRecoveryConstants.ConnectorConfig.ENABLE_AUTO_LGOIN_AFTER_PASSWORD_RESET,
+                testEnableAutoLoginAfterPasswordReset);
+        metaDataExpected.put(IdentityRecoveryConstants.ConnectorConfig.CHALLENGE_QUESTION_ANSWER_REGEX,
+                testChallengeQuestionAnswerRegex);
+        metaDataExpected.put(IdentityRecoveryConstants.ConnectorConfig.RECOVERY_CALLBACK_REGEX,
+                testRecoveryCallbackRegex);
+        metaDataExpected.put(
+                IdentityRecoveryConstants.ConnectorConfig.RECOVERY_NOTIFICATION_PASSWORD_MAX_FAILED_ATTEMPTS,
+                testRecoveryNotificationPasswordMaxFailedAttempts);
+        metaDataExpected.put(
+                IdentityRecoveryConstants.ConnectorConfig.RECOVERY_NOTIFICATION_PASSWORD_MAX_RESEND_ATTEMPTS,
+                testRecoveryNotificationPasswordMaxResendAttempts);
+        metaDataExpected.put(IdentityRecoveryConstants.ConnectorConfig.PASSWORD_RECOVERY_EMAIL_LINK_ENABLE,
+                testPasswordRecoveryEmailLinkEnable);
+        metaDataExpected.put(IdentityRecoveryConstants.ConnectorConfig.PASSWORD_RECOVERY_SMS_OTP_ENABLE,
+                testPasswordRecoverySmsOtpEnable);
+        metaDataExpected.put(IdentityRecoveryConstants.ConnectorConfig.PASSWORD_RECOVERY_SMS_OTP_REGEX,
+                testPasswordRecoverySmsOtpRegex);
+
+        // Fetching actual metadata from the method.
+        Map<String, Property> metaData = recoveryConfigImpl.getMetaData();
+
+        // Asserting that the expected and actual maps are equal.
+        assertEquals(metaData, metaDataExpected);
+    }
+
+
     @Test
     public void testGetDefaultProperties() throws IdentityGovernanceException {
 
diff --git a/components/org.wso2.carbon.identity.recovery/src/test/java/org/wso2/carbon/identity/recovery/internal/service/impl/UserAccountRecoveryManagerTest.java b/components/org.wso2.carbon.identity.recovery/src/test/java/org/wso2/carbon/identity/recovery/internal/service/impl/UserAccountRecoveryManagerTest.java
index 46daf5e74..87e96a880 100644
--- a/components/org.wso2.carbon.identity.recovery/src/test/java/org/wso2/carbon/identity/recovery/internal/service/impl/UserAccountRecoveryManagerTest.java
+++ b/components/org.wso2.carbon.identity.recovery/src/test/java/org/wso2/carbon/identity/recovery/internal/service/impl/UserAccountRecoveryManagerTest.java
@@ -19,6 +19,7 @@
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.MockedStatic;
+import org.mockito.Spy;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.BeforeTest;
@@ -65,11 +66,14 @@
 import java.util.UUID;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.mockStatic;
@@ -88,9 +92,14 @@
  */
 public class UserAccountRecoveryManagerTest {
 
+    private static final String TENANT_DOMAIN = "carbon.super";
+
     @InjectMocks
     private UserAccountRecoveryManager userAccountRecoveryManager;
 
+    @Spy
+    private UserAccountRecoveryManager userAccountRecoveryManagerSpy;
+
     @Mock
     private IdentityRecoveryServiceDataHolder identityRecoveryServiceDataHolder;
 
@@ -175,6 +184,80 @@ public void testRetrieveUserRecoveryInformation() throws Exception {
         testGetUserWithNotificationsInternallyManaged();
     }
 
+    /**
+     * Test retrieve user recovery information for username recovery.
+     *
+     * @throws Exception Error while getting user recovery information
+     */
+    @Test
+    public void testRetrieveUsersRecoveryInformationForUsername() throws Exception {
+
+        ArrayList<org.wso2.carbon.user.core.common.User> userList = new ArrayList<>();
+        userList.add(new org.wso2.carbon.user.core.common.User(UUID.randomUUID().toString(), "user1", "user1"));
+        userList.add(new org.wso2.carbon.user.core.common.User(UUID.randomUUID().toString(), "user2", "user2"));
+
+        doReturn(userList).when(userAccountRecoveryManagerSpy).getUserListByClaims(any(), any());
+
+        mockBuildUser();
+        mockRecoveryConfigs(true);
+        mockUserstoreManager();
+        mockJDBCRecoveryDataStore();
+        mockClaimMetadataManagementService();
+
+        when(abstractUserStoreManager
+                .getUserClaimValues(anyString(), any(String[].class), eq(null))).thenReturn(userClaims);
+        when(IdentityRecoveryServiceDataHolder.getInstance().getIdentityEventService())
+                .thenReturn(identityEventService);
+        doNothing().when(identityEventService).handleEvent(any());
+
+        RecoveryChannelInfoDTO result = userAccountRecoveryManagerSpy.retrieveUsersRecoveryInformationForUsername(null,
+                TENANT_DOMAIN, null);
+
+        assertEquals(result.getNotificationChannelDTOs().length, 2);
+        assertEquals(result.getUsername(), "user2");
+    }
+
+    /**
+     * Test throw no user found error in retrieve user recovery information for username recovery.
+     *
+     * @throws IdentityRecoveryException Exception Error while getting user recovery information
+     */
+    @Test(expectedExceptions = IdentityRecoveryClientException.class)
+    public void testThrowNoUserFoundRetrieveUserRecoveryInformationForUsername() throws IdentityRecoveryException {
+
+        ArrayList<org.wso2.carbon.user.core.common.User> resultedUserList = new ArrayList<>();
+        doReturn(resultedUserList).when(userAccountRecoveryManagerSpy).getUserListByClaims(any(), any());
+        when(Utils.handleClientException(IdentityRecoveryConstants.ErrorMessages.ERROR_CODE_NO_USER_FOUND, null)).
+                thenReturn(new IdentityRecoveryClientException(
+                        null, null, null));
+        userAccountRecoveryManagerSpy.retrieveUsersRecoveryInformationForUsername(null, TENANT_DOMAIN, null);
+    }
+
+    /**
+     * Test throw no user found error when combined usernames become empty in retrieving user recovery information for
+     * username recovery.
+     *
+     * @throws IdentityRecoveryException Exception Error while getting user recovery information
+     */
+    @Test(expectedExceptions = IdentityRecoveryClientException.class)
+    public void testThrowNoUserFoundEmptyUsernamesRetrieveUserRecoveryInformationForUsername()
+            throws IdentityRecoveryException {
+
+        mockBuildUser();
+        ArrayList<org.wso2.carbon.user.core.common.User> resultedUserList = new ArrayList<>();
+        resultedUserList.add(new org.wso2.carbon.user.core.common.User(UUID.randomUUID().toString(), "user1", "user1"));
+        doReturn(resultedUserList).when(userAccountRecoveryManagerSpy).getUserListByClaims(any(), any());
+
+        when(Utils.handleClientException(IdentityRecoveryConstants.ErrorMessages.ERROR_CODE_NO_USER_FOUND, null)).
+                thenReturn(new IdentityRecoveryClientException(
+                        null, null, null));
+        when(Utils.handleClientException(nullable(String.class), anyString(), anyString())).
+                thenReturn(new IdentityRecoveryClientException(
+                        null, null, null));
+        mockedUtils.when(() -> Utils.isAccountDisabled(any(User.class))).thenReturn(true);
+        userAccountRecoveryManagerSpy.retrieveUsersRecoveryInformationForUsername(null, TENANT_DOMAIN, null);
+    }
+
     /**
      * Tests that a NullPointerException is thrown during user recovery when a UserStoreException
      * occurs.
diff --git a/components/org.wso2.carbon.identity.recovery/src/test/java/org/wso2/carbon/identity/recovery/internal/service/impl/username/UsernameRecoveryManagerImplTest.java b/components/org.wso2.carbon.identity.recovery/src/test/java/org/wso2/carbon/identity/recovery/internal/service/impl/username/UsernameRecoveryManagerImplTest.java
index d12714ab7..e96fb1225 100644
--- a/components/org.wso2.carbon.identity.recovery/src/test/java/org/wso2/carbon/identity/recovery/internal/service/impl/username/UsernameRecoveryManagerImplTest.java
+++ b/components/org.wso2.carbon.identity.recovery/src/test/java/org/wso2/carbon/identity/recovery/internal/service/impl/username/UsernameRecoveryManagerImplTest.java
@@ -25,10 +25,14 @@
 import org.wso2.carbon.identity.application.common.model.User;
 import org.wso2.carbon.identity.core.util.IdentityUtil;
 import org.wso2.carbon.identity.event.services.IdentityEventService;
+import org.wso2.carbon.identity.governance.service.notification.NotificationChannels;
 import org.wso2.carbon.identity.recovery.IdentityRecoveryClientException;
 import org.wso2.carbon.identity.recovery.IdentityRecoveryConstants;
 import org.wso2.carbon.identity.recovery.IdentityRecoveryException;
+import org.wso2.carbon.identity.recovery.RecoveryScenarios;
 import org.wso2.carbon.identity.recovery.RecoverySteps;
+import org.wso2.carbon.identity.recovery.dto.NotificationChannelDTO;
+import org.wso2.carbon.identity.recovery.dto.RecoveryChannelInfoDTO;
 import org.wso2.carbon.identity.recovery.dto.RecoveryInformationDTO;
 import org.wso2.carbon.identity.recovery.dto.UsernameRecoverDTO;
 import org.wso2.carbon.identity.recovery.internal.IdentityRecoveryServiceDataHolder;
@@ -42,15 +46,19 @@
 import java.net.URLDecoder;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.mockStatic;
 import static org.mockito.Mockito.when;
 import static org.mockito.MockitoAnnotations.openMocks;
 import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
 
 /**
  * Test class for UsernameRecoveryManagerImpl.
@@ -152,9 +160,10 @@ public void testConfigValidation() throws IdentityRecoveryException {
      */
     @DataProvider
     public Object[][] channelIDProvider() {
-        return new Object[][] {
-                { null },
-                { "0" }
+
+        return new Object[][]{
+                {null},
+                {"0"}
         };
     }
 
@@ -188,7 +197,8 @@ public void testInvalidateRecoveryCode() throws IdentityRecoveryException {
         Map<String, String> properties = new HashMap<>();
         properties.put("useLegacyAPI", FALSE);
         mockedJDBCRecoveryDataStore.when(JDBCRecoveryDataStore::getInstance).thenReturn(mockUserRecoveryDataStore);
-        mockedRecoveryManagerStatic.when(UserAccountRecoveryManager::getInstance).thenReturn(mockUserAccountRecoveryManager);
+        mockedRecoveryManagerStatic.when(UserAccountRecoveryManager::getInstance)
+                .thenReturn(mockUserAccountRecoveryManager);
         when(mockUserAccountRecoveryManager.getUserRecoveryData(recoveryCode, RecoverySteps.SEND_RECOVERY_INFORMATION))
                 .thenReturn(mockUserRecoveryData);
         when(Utils.getRecoveryConfigs(anyString(), anyString())).thenReturn(TRUE);
@@ -207,7 +217,8 @@ public void testInvalidateRecoveryCodeWithException() throws IdentityRecoveryExc
         Map<String, String> properties = new HashMap<>();
         properties.put("useLegacyAPI", FALSE);
         mockedJDBCRecoveryDataStore.when(JDBCRecoveryDataStore::getInstance).thenReturn(mockUserRecoveryDataStore);
-        mockedRecoveryManagerStatic.when(UserAccountRecoveryManager::getInstance).thenReturn(mockUserAccountRecoveryManager);
+        mockedRecoveryManagerStatic.when(UserAccountRecoveryManager::getInstance)
+                .thenReturn(mockUserAccountRecoveryManager);
         when(mockUserAccountRecoveryManager.getUserRecoveryData(recoveryCode, RecoverySteps.SEND_RECOVERY_INFORMATION))
                 .thenReturn(mockUserRecoveryData);
         when(mockUserRecoveryData.getRecoveryFlowId()).thenReturn("FlowID");
@@ -227,7 +238,8 @@ public void testExtractChannelDetails() throws IdentityRecoveryException {
         Map<String, String> properties = new HashMap<>();
         properties.put("useLegacyAPI", FALSE);
         mockedJDBCRecoveryDataStore.when(JDBCRecoveryDataStore::getInstance).thenReturn(mockUserRecoveryDataStore);
-        mockedRecoveryManagerStatic.when(UserAccountRecoveryManager::getInstance).thenReturn(mockUserAccountRecoveryManager);
+        mockedRecoveryManagerStatic.when(UserAccountRecoveryManager::getInstance)
+                .thenReturn(mockUserAccountRecoveryManager);
         when(mockUserAccountRecoveryManager.getUserRecoveryData(recoveryCode, RecoverySteps.SEND_RECOVERY_INFORMATION))
                 .thenReturn(mockUserRecoveryData);
         when(mockUserRecoveryData.getRemainingSetIds()).thenReturn("123");
@@ -249,19 +261,21 @@ public void testNotifyUser() throws IdentityRecoveryException {
         Map<String, String> properties = new HashMap<>();
         properties.put("useLegacyAPI", FALSE);
         mockedJDBCRecoveryDataStore.when(JDBCRecoveryDataStore::getInstance).thenReturn(mockUserRecoveryDataStore);
-        mockedRecoveryManagerStatic.when(UserAccountRecoveryManager::getInstance).thenReturn(mockUserAccountRecoveryManager);
+        mockedRecoveryManagerStatic.when(UserAccountRecoveryManager::getInstance)
+                .thenReturn(mockUserAccountRecoveryManager);
         when(mockUserAccountRecoveryManager.getUserRecoveryData(recoveryCode, RecoverySteps.SEND_RECOVERY_INFORMATION))
                 .thenReturn(mockUserRecoveryData);
         when(mockUserRecoveryData.getRemainingSetIds()).thenReturn("EXTERNAL,EXTERNAL");
         when(Utils.getRecoveryConfigs(anyString(), anyString())).thenReturn(TRUE);
         User mockUser = new User();
-        mockUser.setUserName("KD123");
+        mockUser.setUserName("user1,user2");
         mockUser.setTenantDomain(TENANT_DOMAIN);
         when(mockUserRecoveryData.getUser()).thenReturn(mockUser);
         when(Utils.handleClientException(IdentityRecoveryConstants.ErrorMessages.ERROR_CODE_INVALID_CHANNEL_ID, null))
                 .thenReturn(new IdentityRecoveryClientException(null));
         UsernameRecoverDTO code = usernameRecoveryManager.notify(recoveryCode, "2", TENANT_DOMAIN, properties);
         assertEquals(code.getCode(), "UNR-02002");
+        assertEquals(code.getUsername(), String.format("user1@%s,user2@%s", TENANT_DOMAIN, TENANT_DOMAIN));
     }
 
     /**
@@ -277,7 +291,8 @@ public void testNotifyUserException() throws IdentityRecoveryException {
         Map<String, String> properties = new HashMap<>();
         properties.put("useLegacyAPI", FALSE);
         mockedJDBCRecoveryDataStore.when(JDBCRecoveryDataStore::getInstance).thenReturn(mockUserRecoveryDataStore);
-        mockedRecoveryManagerStatic.when(UserAccountRecoveryManager::getInstance).thenReturn(mockUserAccountRecoveryManager);
+        mockedRecoveryManagerStatic.when(UserAccountRecoveryManager::getInstance)
+                .thenReturn(mockUserAccountRecoveryManager);
         when(mockUserAccountRecoveryManager.getUserRecoveryData(recoveryCode, RecoverySteps.SEND_RECOVERY_INFORMATION))
                 .thenReturn(mockUserRecoveryData);
         when(mockUserRecoveryData.getRemainingSetIds()).thenReturn("SMS,SMS");
@@ -289,7 +304,8 @@ public void testNotifyUserException() throws IdentityRecoveryException {
         when(mockUserRecoveryData.getUser()).thenReturn(mockUser);
         UsernameRecoverDTO result = usernameRecoveryManager.notify(recoveryCode, "2", TENANT_DOMAIN, properties);
         assertEquals(result.getCode(), "UNR-02001");
-        assertEquals(result.getMessage(), "Username recovery information sent via user preferred notification channel.");
+        assertEquals(result.getMessage(),
+                "Username recovery information sent via user preferred notification channel.");
     }
 
     /**
@@ -307,7 +323,8 @@ public void testCallbackURLValidation() throws IdentityRecoveryException {
         properties.put("useLegacyAPI", TRUE);
         properties.put(IdentityRecoveryConstants.CALLBACK, callbackURL);
         mockedJDBCRecoveryDataStore.when(JDBCRecoveryDataStore::getInstance).thenReturn(mockUserRecoveryDataStore);
-        mockedRecoveryManagerStatic.when(UserAccountRecoveryManager::getInstance).thenReturn(mockUserAccountRecoveryManager);
+        mockedRecoveryManagerStatic.when(UserAccountRecoveryManager::getInstance)
+                .thenReturn(mockUserAccountRecoveryManager);
         when(mockUserAccountRecoveryManager.getUserRecoveryData(recoveryCode, RecoverySteps.SEND_RECOVERY_INFORMATION))
                 .thenReturn(mockUserRecoveryData);
         when(mockUserRecoveryData.getRemainingSetIds()).thenReturn("SMS,SMS");
@@ -338,13 +355,15 @@ public void testCallbackURLDecoding() throws IdentityRecoveryException {
         properties.put("useLegacyAPI", TRUE);
         properties.put(IdentityRecoveryConstants.CALLBACK, callbackURL);
         mockedJDBCRecoveryDataStore.when(JDBCRecoveryDataStore::getInstance).thenReturn(mockUserRecoveryDataStore);
-        mockedRecoveryManagerStatic.when(UserAccountRecoveryManager::getInstance).thenReturn(mockUserAccountRecoveryManager);
+        mockedRecoveryManagerStatic.when(UserAccountRecoveryManager::getInstance)
+                .thenReturn(mockUserAccountRecoveryManager);
         when(mockUserAccountRecoveryManager.getUserRecoveryData(recoveryCode, RecoverySteps.SEND_RECOVERY_INFORMATION))
                 .thenReturn(mockUserRecoveryData);
         when(mockUserRecoveryData.getRemainingSetIds()).thenReturn("SMS,SMS");
         when(Utils.getRecoveryConfigs(anyString(), anyString())).thenReturn(TRUE);
         when(Utils.resolveEventName(anyString())).thenReturn("TRIGGER_SMS_NOTIFICATION_LOCAL");
-        mockURLDecoder.when(() -> URLDecoder.decode(anyString(), anyString())).thenThrow(new UnsupportedEncodingException());
+        mockURLDecoder.when(() -> URLDecoder.decode(anyString(), anyString()))
+                .thenThrow(new UnsupportedEncodingException());
         usernameRecoveryManager.notify(recoveryCode, "2", TENANT_DOMAIN, properties);
     }
 
@@ -366,7 +385,8 @@ public void testInitiateRecoveryWithNullUsername() throws IdentityRecoveryExcept
         properties.put("useLegacyAPI", TRUE);
         when(Utils.getRecoveryConfigs(anyString(), anyString())).thenReturn(TRUE);
         mockedJDBCRecoveryDataStore.when(JDBCRecoveryDataStore::getInstance).thenReturn(mockUserRecoveryDataStore);
-        mockedRecoveryManagerStatic.when(UserAccountRecoveryManager::getInstance).thenReturn(mockUserAccountRecoveryManager);
+        mockedRecoveryManagerStatic.when(UserAccountRecoveryManager::getInstance)
+                .thenReturn(mockUserAccountRecoveryManager);
         when(mockUserAccountRecoveryManager.getUserListByClaims(null, TENANT_DOMAIN)).thenReturn(userList);
         when(IdentityUtil.getProperty(anyString())).thenReturn(TRUE);
         when(Utils.handleClientException(IdentityRecoveryConstants.ErrorMessages.ERROR_CODE_NO_USER_FOUND, null))
@@ -391,7 +411,8 @@ public void testInitiateRecoveryValidUsername() throws IdentityRecoveryException
         properties.put("useLegacyAPI", TRUE);
         when(Utils.getRecoveryConfigs(anyString(), anyString())).thenReturn(TRUE);
         mockedJDBCRecoveryDataStore.when(JDBCRecoveryDataStore::getInstance).thenReturn(mockUserRecoveryDataStore);
-        mockedRecoveryManagerStatic.when(UserAccountRecoveryManager::getInstance).thenReturn(mockUserAccountRecoveryManager);
+        mockedRecoveryManagerStatic.when(UserAccountRecoveryManager::getInstance)
+                .thenReturn(mockUserAccountRecoveryManager);
         when(mockUserAccountRecoveryManager.getUserListByClaims(null, TENANT_DOMAIN)).thenReturn(userList);
         when(IdentityUtil.getProperty(anyString())).thenReturn(TRUE);
         when(Utils.isNotificationsInternallyManaged(TENANT_DOMAIN, properties)).thenReturn(true);
@@ -401,6 +422,71 @@ public void testInitiateRecoveryValidUsername() throws IdentityRecoveryException
         assertEquals(result.getUsername(), "testUser");
     }
 
+    /**
+     * Test to initiate recovery with useLegacyAPI false.
+     *
+     * @throws IdentityRecoveryException if an error occurs during initiation.
+     */
+    @Test
+    public void testInitiateRecoveryWithUseLegacyAPIFalse() throws IdentityRecoveryException {
+
+        String TEST_USER = "testUser";
+        mockIdentityEventService();
+        RecoveryChannelInfoDTO recoveryChannelInfoDTO = new RecoveryChannelInfoDTO();
+        recoveryChannelInfoDTO.setUsername("testUser");
+        List<NotificationChannelDTO> notificationChannelDTOList = new ArrayList<>();
+
+        NotificationChannelDTO notificationChannelDTO1 = new NotificationChannelDTO();
+        notificationChannelDTO1.setId(1);
+        notificationChannelDTO1.setType(NotificationChannels.EMAIL_CHANNEL.getChannelType());
+
+        NotificationChannelDTO notificationChannelDTO2 = new NotificationChannelDTO();
+        notificationChannelDTO2.setId(2);
+        notificationChannelDTO2.setType(NotificationChannels.SMS_CHANNEL.getChannelType());
+
+        notificationChannelDTOList.add(notificationChannelDTO1);
+        notificationChannelDTOList.add(notificationChannelDTO2);
+        recoveryChannelInfoDTO.setNotificationChannelDTOs(
+                notificationChannelDTOList.toArray(new NotificationChannelDTO[0]));
+
+        Map<String, String> properties = new HashMap<>();
+        when(Utils.getRecoveryConfigs(anyString(), anyString())).thenReturn(TRUE);
+
+        // Case 1: When Recovery.Notification.Username.NonUniqueUsername is enabled.
+        when(IdentityUtil.getProperty(
+                eq(IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_NON_UNIQUE_USERNAME))).thenReturn(TRUE);
+
+        mockedRecoveryManagerStatic.when(UserAccountRecoveryManager::getInstance)
+                .thenReturn(mockUserAccountRecoveryManager);
+        when(mockUserAccountRecoveryManager.retrieveUsersRecoveryInformationForUsername(eq(null), eq(TENANT_DOMAIN),
+                any())).thenReturn(recoveryChannelInfoDTO);
+        when(Utils.isNotificationsInternallyManaged(TENANT_DOMAIN, properties)).thenReturn(true);
+        RecoveryInformationDTO result = usernameRecoveryManager.initiate(null, TENANT_DOMAIN, properties);
+        assertEquals(result.getRecoveryChannelInfoDTO().getUsername(), TEST_USER);
+        assertEquals(result.getRecoveryChannelInfoDTO().getNotificationChannelDTOs().length, 2);
+
+        // Case 2: When Recovery.Notification.Username.NonUniqueUsername is disabled.
+        when(IdentityUtil.getProperty(
+                eq(IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_NON_UNIQUE_USERNAME))).thenReturn(FALSE);
+        when(mockUserAccountRecoveryManager.retrieveUserRecoveryInformation(eq(null), eq(TENANT_DOMAIN),
+                eq(RecoveryScenarios.USERNAME_RECOVERY),
+                any())).thenReturn(recoveryChannelInfoDTO);
+        result = usernameRecoveryManager.initiate(null, TENANT_DOMAIN, properties);
+        assertEquals(result.getRecoveryChannelInfoDTO().getUsername(), TEST_USER);
+        assertEquals(result.getRecoveryChannelInfoDTO().getNotificationChannelDTOs().length, 2);
+
+        // Case 3: Disable the sms channel.
+        when(Utils.getRecoveryConfigs(eq(IdentityRecoveryConstants.ConnectorConfig.USERNAME_RECOVERY_SMS_ENABLE),
+                eq(TENANT_DOMAIN)))
+                .thenReturn(FALSE);
+        result = usernameRecoveryManager.initiate(null, TENANT_DOMAIN, properties);
+        assertEquals(result.getRecoveryChannelInfoDTO().getUsername(), TEST_USER);
+        assertEquals(result.getRecoveryChannelInfoDTO().getNotificationChannelDTOs().length, 1);
+        assertEquals(result.getRecoveryChannelInfoDTO().getNotificationChannelDTOs()[0].getType(),
+                NotificationChannels.EMAIL_CHANNEL.getChannelType());
+
+    }
+
     /**
      * Mock the IdentityEventService.
      */