diff --git a/libmultipath/config.c b/libmultipath/config.c
index 6b236019..fa42dcd9 100644
--- a/libmultipath/config.c
+++ b/libmultipath/config.c
@@ -176,6 +176,9 @@ free_hwe (struct hwentry * hwe)
 	if (hwe->uid_attribute)
 		FREE(hwe->uid_attribute);
 
+	if (hwe->uid_reference)
+		FREE(hwe->uid_reference);
+
 	if (hwe->features)
 		FREE(hwe->features);
 
@@ -236,6 +239,9 @@ free_mpe (struct mpentry * mpe)
 	if (mpe->uid_attribute)
 		FREE(mpe->uid_attribute);
 
+	if (mpe->uid_reference)
+		FREE(mpe->uid_reference);
+
 	if (mpe->alias)
 		FREE(mpe->alias);
 
@@ -323,6 +329,7 @@ merge_hwe (struct hwentry * dst, struct hwentry * src)
 	merge_str(revision);
 	merge_str(getuid);
 	merge_str(uid_attribute);
+	merge_str(uid_reference);
 	merge_str(features);
 	merge_str(hwhandler);
 	merge_str(selector);
@@ -388,6 +395,9 @@ store_hwe (vector hwtable, struct hwentry * dhwe)
 	if (dhwe->uid_attribute && !(hwe->uid_attribute = set_param_str(dhwe->uid_attribute)))
 		goto out;
 
+	if (dhwe->uid_reference && !(hwe->uid_reference = set_param_str(dhwe->uid_reference)))
+		goto out;
+
 	if (dhwe->getuid && !(hwe->getuid = set_param_str(dhwe->getuid)))
 		goto out;
 
@@ -500,6 +510,9 @@ free_config (struct config * conf)
 	if (conf->uid_attribute)
 		FREE(conf->uid_attribute);
 
+	if (conf->uid_reference)
+		FREE(conf->uid_reference);
+
 	if (conf->uid_attrs)
 		FREE(conf->uid_attrs);
 
diff --git a/libmultipath/config.h b/libmultipath/config.h
index ffc69b5f..709e9f19 100644
--- a/libmultipath/config.h
+++ b/libmultipath/config.h
@@ -47,6 +47,7 @@ struct hwentry {
 	char * product;
 	char * revision;
 	char * uid_attribute;
+	char * uid_reference;
 	char * getuid;
 	char * features;
 	char * hwhandler;
@@ -84,6 +85,7 @@ struct mpentry {
 	char * wwid;
 	char * alias;
 	char * uid_attribute;
+	char * uid_reference;
 	char * getuid;
 	char * selector;
 	char * features;
@@ -172,6 +174,7 @@ struct config {
 	char * selector;
 	char * uid_attrs;
 	char * uid_attribute;
+	char * uid_reference;
 	char * getuid;
 	char * features;
 	char * hwhandler;
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
index 82066f67..7a5514ad 100644
--- a/libmultipath/dict.c
+++ b/libmultipath/dict.c
@@ -258,6 +258,14 @@ declare_ovr_snprint(uid_attribute, print_str)
 declare_hw_handler(uid_attribute, set_str)
 declare_hw_snprint(uid_attribute, print_str)
 
+declare_def_handler(uid_reference, set_str)
+declare_def_snprint(uid_reference, print_str)
+declare_ovr_handler(uid_reference, set_str)
+declare_ovr_snprint(uid_reference, print_str)
+declare_hw_handler(uid_reference, set_str)
+declare_hw_snprint(uid_reference, print_str)
+
+
 declare_def_handler(getuid, set_str)
 declare_def_snprint(getuid, print_str)
 declare_ovr_handler(getuid, set_str)
@@ -1400,6 +1408,7 @@ init_keywords(vector keywords)
 	install_keyword("path_grouping_policy", &def_pgpolicy_handler, &snprint_def_pgpolicy);
 	install_keyword("uid_attrs", &def_uid_attrs_handler, &snprint_def_uid_attrs);
 	install_keyword("uid_attribute", &def_uid_attribute_handler, &snprint_def_uid_attribute);
+	install_keyword("uid_reference", &def_uid_reference_handler, &snprint_def_uid_reference);
 	install_keyword("getuid_callout", &def_getuid_handler, &snprint_def_getuid);
 	install_keyword("prio", &def_prio_name_handler, &snprint_def_prio_name);
 	install_keyword("prio_args", &def_prio_args_handler, &snprint_def_prio_args);
@@ -1499,6 +1508,7 @@ init_keywords(vector keywords)
 	install_keyword("product_blacklist", &hw_bl_product_handler, &snprint_hw_bl_product);
 	install_keyword("path_grouping_policy", &hw_pgpolicy_handler, &snprint_hw_pgpolicy);
 	install_keyword("uid_attribute", &hw_uid_attribute_handler, &snprint_hw_uid_attribute);
+	install_keyword("uid_reference", &hw_uid_reference_handler, &snprint_hw_uid_reference);
 	install_keyword("getuid_callout", &hw_getuid_handler, &snprint_hw_getuid);
 	install_keyword("path_selector", &hw_selector_handler, &snprint_hw_selector);
 	install_keyword("path_checker", &hw_checker_name_handler, &snprint_hw_checker_name);
@@ -1534,6 +1544,7 @@ init_keywords(vector keywords)
 	install_keyword_root("overrides", &overrides_handler);
 	install_keyword("path_grouping_policy", &ovr_pgpolicy_handler, &snprint_ovr_pgpolicy);
 	install_keyword("uid_attribute", &ovr_uid_attribute_handler, &snprint_ovr_uid_attribute);
+	install_keyword("uid_reference", &ovr_uid_reference_handler, &snprint_ovr_uid_reference);
 	install_keyword("getuid_callout", &ovr_getuid_handler, &snprint_ovr_getuid);
 	install_keyword("path_selector", &ovr_selector_handler, &snprint_ovr_selector);
 	install_keyword("path_checker", &ovr_checker_name_handler, &snprint_ovr_checker_name);
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
index 1d3f591e..ce2343cd 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -1768,6 +1768,118 @@ get_vpd_uid(struct path * pp)
 	return get_vpd_sysfs(parent, 0x83, pp->wwid, WWID_SIZE);
 }
 
+static int
+check_uid_reference(struct path * pp, char *uid_reference)
+{
+	const char *msg_id = "uid_reference";
+	const char *from_dev;
+	const char *to_dev_regex;
+	char *args, *temp;
+	char split_char[] = " \t";
+	regex_t path_regex;
+	int ret = -EINVAL;
+
+	if (!uid_reference)
+		return -EINVAL;
+
+	args = temp = STRDUP(uid_reference);
+	if (!args)
+		return -ENOMEM;
+
+	to_dev_regex = get_next_string(&temp, split_char);
+	if (!to_dev_regex) {
+		condlog(3, "%s: no target devices provided for %s",
+			pp->dev, msg_id);
+		goto out1;
+	}
+
+	if (!temp || !(from_dev = get_next_string(&temp, split_char))) {
+		condlog(3, "%s: no source device provided for %s",
+			pp->dev, msg_id);
+		goto out1;
+	}
+
+	if (regcomp(&path_regex, to_dev_regex, REG_EXTENDED|REG_NOSUB))
+		goto out2;
+
+	/*
+	 * to discard if the target device is in the source device list
+	 */
+	if (!regexec(&path_regex, from_dev, 0, NULL, 0)) {
+		condlog(3, "%s: invalid parameter for %s because the source \
+			devices include the target device", pp->dev, msg_id);
+		goto out2;
+	}
+
+	if (regexec(&path_regex, pp->dev, 0, NULL, 0)) {
+		goto out2;
+	}
+
+	ret = 0;
+out2:
+	regfree(&path_regex);
+out1:
+	FREE(args);
+
+	return ret;
+}
+
+static int
+get_uid_reference(struct path * pp, char *uid_reference)
+{
+	const char *msg_id = "uid_reference";
+	int ret;
+	ssize_t len = -1;
+
+	const char *from_dev = NULL;
+	char *args, *temp;
+	char split_char[] = " \t";
+	struct path *from_pp = NULL;
+	struct udev_device *from_udev;
+	struct config *conf;
+
+	args = temp = STRDUP(uid_reference);
+	if (!args)
+		return -ENOMEM;
+
+	/*
+	 * the uid_reference has been checked by check_uid_reference,
+	 * so discard handle the exceptions
+	 */
+	get_next_string(&temp, split_char);
+	from_dev = get_next_string(&temp, split_char);
+
+	from_udev = udev_device_new_from_subsystem_sysname(udev, "block",
+			from_dev);
+	if (!from_udev) {
+		condlog(3, "%s: (%s) failed to get udev_device for (%s)",
+			pp->dev, msg_id, from_dev);
+		goto out1;
+	}
+
+	conf = get_multipath_config();
+	ret = alloc_path_with_pathinfo(conf, from_udev, NULL,
+			DI_SYSFS | DI_WWID | DI_BLACKLIST,
+			&from_pp, PATHFLAG_UID_TO_BE_REFERENCED);
+	put_multipath_config(conf);
+
+	if (!from_pp || ret) {
+		condlog(3, "%s: (%s) failed to get source device (%s)\'s wwid",
+			pp->dev, msg_id, from_dev);
+		goto out2;
+	}
+
+	if (strlen(from_pp->wwid) != 0) {
+		len = strlcpy(pp->wwid, from_pp->wwid, WWID_SIZE);
+	}
+out2:
+	udev_device_unref(from_udev);
+out1:
+	FREE(args);
+
+	return len;
+}
+
 int
 get_uid (struct path * pp, int path_state, struct udev_device *udev)
 {
@@ -1775,8 +1887,9 @@ get_uid (struct path * pp, int path_state, struct udev_device *udev)
 	const char *origin = "unknown";
 	ssize_t len = 0;
 	struct config *conf;
+	int flag;
 
-	if (!pp->uid_attribute && !pp->getuid) {
+	if (!pp->uid_attribute && !pp->getuid && !pp->uid_reference) {
 		conf = get_multipath_config();
 		select_getuid(conf, pp);
 		put_multipath_config(conf);
@@ -1788,7 +1901,13 @@ get_uid (struct path * pp, int path_state, struct udev_device *udev)
 	}
 
 	memset(pp->wwid, 0, WWID_SIZE);
-	if (pp->getuid) {
+
+	flag = pp->flags & PATHFLAG_UID_TO_BE_REFERENCED;
+	if (!flag && check_uid_reference(pp, pp->uid_reference) == 0) {
+		len = get_uid_reference(pp, pp->uid_reference);
+		origin = "reference";
+	}
+	else if (pp->getuid) {
 		char buff[CALLOUT_MAX_SIZE];
 
 		/* Use 'getuid' callout, deprecated */
diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c
index 27f39517..75c339c1 100644
--- a/libmultipath/propsel.c
+++ b/libmultipath/propsel.c
@@ -343,10 +343,35 @@ out:
 	return 0;
 }
 
+static int select_uid_reference(struct config *conf, struct path *pp)
+{
+	char *origin;
+	int flag = pp->flags & PATHFLAG_UID_TO_BE_REFERENCED;
+
+	if (!flag) {
+		pp_set_ovr(uid_reference);
+		pp_set_hwe(uid_reference);
+		pp_set_conf(uid_reference);
+	}
+
+out:
+	if (pp->uid_reference)
+		condlog(3, "%s: uid_reference = %s %s", pp->dev,
+			pp->uid_reference, origin);
+	return 0;
+
+}
+
 int select_getuid(struct config *conf, struct path *pp)
 {
 	char *origin;
 
+	/*
+	 * Here we use a wrapper to ensure uid_reference can be fetched
+	 * with either getuid or uid_atrribute.
+	 */
+	select_uid_reference(conf, pp);
+
 	pp->uid_attribute = parse_uid_attribute_by_attrs(conf->uid_attrs, pp->dev);
 	if (pp->uid_attribute) {
 		origin = "(setting: multipath.conf defaults section)";
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
index 0d2bc40d..e548059d 100644
--- a/libmultipath/structs.h
+++ b/libmultipath/structs.h
@@ -222,6 +222,7 @@ struct path {
 	int wait_checks;
 	int tpgs;
 	char * uid_attribute;
+	char * uid_reference;
 	char * getuid;
 	struct prio prio;
 	char * prio_args;
diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
index 22be8e0d..ed5c94df 100644
--- a/libmultipath/structs_vec.c
+++ b/libmultipath/structs_vec.c
@@ -85,6 +85,7 @@ void orphan_path(struct path *pp, const char *reason)
 	pp->mpp = NULL;
 	pp->dmstate = PSTATE_UNDEF;
 	pp->uid_attribute = NULL;
+	pp->uid_reference = NULL;
 	pp->getuid = NULL;
 	prio_put(&pp->prio);
 	checker_put(&pp->checker);
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
index 0049cba7..e2916ac6 100644
--- a/multipath/multipath.conf.5
+++ b/multipath/multipath.conf.5
@@ -238,6 +238,22 @@ The default is: for NVME devices \fBID_WWN\fR
 .
 .
 .TP
+.B uid_reference
+The user defined attribute providing a unique path identifier by referencing
+another path's identifier. Those paths can be coalesced. This is useful to
+migrate data for heterogenous arrays without interrupting uplayer transaction.
+If you are going to let sda, sdb and sdc use the unique path identifier of the sdd,
+you can set uid_reference as:
+.RS
+.TP
+\fBsd[a-c]  sdd\fR
+where the first parameter which can be regular expression is the target devices
+to be assigned. The second parameter is the source device whose identifier will be
+referenced by the target devices. The source device only support one device.
+.RE
+.
+.
+.TP
 .B getuid_callout
 (Superseded by \fIuid_attribute\fR) The default program and args to callout
 to obtain a unique path identifier. Should be specified with an absolute path.
@@ -1193,6 +1209,8 @@ section:
 .TP
 .B uid_attribute
 .TP
+.B uid_reference
+.TP
 .B path_selector
 .TP
 .B path_checker
@@ -1259,6 +1277,8 @@ the values are taken from the \fIdevices\fR or \fIdefaults\fR sections:
 .TP
 .B uid_attribute
 .TP
+.B uid_reference
+.TP
 .B getuid_callout
 .TP
 .B path_selector
@@ -1323,8 +1343,23 @@ Multipath uses a \fIWorld Wide Identification\fR (WWID) to determine
 which paths belong to the same device. Each path presenting the same
 WWID is assumed to point to the same device.
 .LP
-The WWID is generated by three methods (in the order of preference):
+The WWID is generated by four methods (in the order of preference):
 .TP 17
+.B uid_reference
+The user defined attribute providing a unique path identifier by referencing
+another path's identifier. Those paths can be coalesced. This is useful to
+migrate data for heterogenous arrays without interrupting uplayer transaction.
+If you are going to let sda, sdb and sdc use the unique path identifier of the sdd,
+you can set uid_reference as:
+.RS
+.TP
+\fBsd[a-c]  sdd\fR
+where the first parameter which can be regular expression is the target devices
+to be assigned. The second parameter is the source device whose identifier will be
+referenced by the target devices. The source device only support one device.
+.RE
+.
+.TP
 .B getuid_callout
 Use the specified external program; cf \fIgetuid_callout\fR above.
 Care should be taken when using this method; the external program
