data type CHANGE clarify and simplify information about lyd_value's type
diff --git a/src/plugins_types.c b/src/plugins_types.c
index 7445972..62e3498 100644
--- a/src/plugins_types.c
+++ b/src/plugins_types.c
@@ -50,7 +50,7 @@
  * Implementation of the ly_type_free_clb.
  */
 static void
-ly_type_free_canonical(struct ly_ctx *ctx, struct lysc_type *UNUSED(type), struct lyd_value *value)
+ly_type_free_canonical(struct ly_ctx *ctx, struct lyd_value *value)
 {
     lydict_remove(ctx, value->canonized);
     value->canonized = NULL;
@@ -901,12 +901,12 @@
  * Implementation of the ly_type_free_clb.
  */
 static void
-ly_type_free_bits(struct ly_ctx *ctx, struct lysc_type *type, struct lyd_value *value)
+ly_type_free_bits(struct ly_ctx *ctx, struct lyd_value *value)
 {
     LY_ARRAY_FREE(value->bits_items);
     value->bits_items = NULL;
 
-    ly_type_free_canonical(ctx, type, value);
+    ly_type_free_canonical(ctx, value);
 }
 
 
@@ -1347,7 +1347,7 @@
     pred->value = calloc(1, sizeof *pred->value);
 
     type = ((struct lysc_node_leaf*)key)->type;
-    pred->value->plugin = type->plugin;
+    pred->value->realtype = type;
     ret = type->plugin->store(ctx, type, val, val_len, options, ly_type_stored_prefixes_clb, prefixes, format, key, NULL,
                               pred->value, NULL, &err);
     if (ret == LY_EINCOMPLETE) {
@@ -1438,7 +1438,7 @@
             asprintf(&errmsg, "Invalid instance-identifier \"%s\" value - required instance not found.",
                      "TODO");
             /* we have to clean up the storage */
-            type->plugin->free(ctx, type, storage);
+            type->plugin->free(ctx, storage);
 
             goto error;
         }
@@ -1811,12 +1811,12 @@
  * Implementation of the ly_type_free_clb.
  */
 static void
-ly_type_free_instanceid(struct ly_ctx *ctx, struct lysc_type *type, struct lyd_value *value)
+ly_type_free_instanceid(struct ly_ctx *ctx, struct lyd_value *value)
 {
     lyd_value_free_path(ctx, value->target);
     value->target = NULL;
 
-    ly_type_free_canonical(ctx, type, value);
+    ly_type_free_canonical(ctx, value);
 }
 
 /**
@@ -1848,7 +1848,7 @@
         storage_dummy = 1;
     }
     /* rewrite leafref plugin stored in the storage by default */
-    storage->plugin = type_lr->realtype->plugin;
+    storage->realtype = type_lr->realtype;
 
     /* check value according to the real type of the leafref target */
     ret = type_lr->realtype->plugin->store(ctx, type_lr->realtype, value, value_len, options,
@@ -2010,7 +2010,7 @@
                 } while (*token != ']');
 
                 /* compare key and the value */
-                if (key->value.plugin->compare(&key->value, &((struct lyd_node_term*)value)->value)) {
+                if (key->value.realtype->plugin->compare(&key->value, &((struct lyd_node_term*)value)->value)) {
                     /* nodes does not match, try another instance */
 next_instance:
                     token = first_pred;
@@ -2048,7 +2048,7 @@
     }
 
     if (storage_dummy) {
-        storage->plugin->free(ctx, type_lr->realtype, storage);
+        storage->realtype->plugin->free(ctx, storage);
         free(storage);
     }
     return ret;
@@ -2058,7 +2058,7 @@
         *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_RESTRICTION, errmsg, NULL, NULL);
     }
     if (storage_dummy) {
-        storage->plugin->free(ctx, type_lr->realtype, storage);
+        storage->realtype->plugin->free(ctx, storage);
         free(storage);
     }
     return LY_EVALID;
@@ -2073,7 +2073,7 @@
 static LY_ERR
 ly_type_compare_leafref(const struct lyd_value *val1, const struct lyd_value *val2)
 {
-    return val1->plugin->compare(val1, val2);
+    return val1->realtype->plugin->compare(val1, val2);
 }
 
 /**
@@ -2082,11 +2082,9 @@
  * Implementation of the ly_type_free_clb.
  */
 static void
-ly_type_free_leafref(struct ly_ctx *ctx, struct lysc_type *type, struct lyd_value *value)
+ly_type_free_leafref(struct ly_ctx *ctx, struct lyd_value *value)
 {
-    struct lysc_type *realtype = ((struct lysc_type_leafref*)type)->realtype;
-
-    realtype->plugin->free(ctx, realtype, value);
+    value->realtype->plugin->free(ctx, value);
 }
 
 /**
@@ -2113,12 +2111,24 @@
          * about the second call to avoid rewriting the canonized value */
         secondcall = 1;
 
-        /* get u of the used type to call the store callback second time, if it fails
-         * we are continuing with another type in row, anyway now we should have the data */
-        LY_ARRAY_FOR(type_u->types, u) {
-            if (type_u->types[u] == subvalue->type) {
-                goto search_subtype;
-            }
+        /* call the callback second time */
+        ret = subvalue->value->realtype->plugin->store(ctx, subvalue->value->realtype, value, value_len,
+                                                       options & ~(LY_TYPE_OPTS_CANONIZE | LY_TYPE_OPTS_DYNAMIC),
+                                                       ly_type_stored_prefixes_clb, subvalue->prefixes, format,
+                                                       context_node, trees, subvalue->value, NULL, err);
+        if (ret) {
+            /* second call failed, we have to try another subtype of the union.
+             * Unfortunately, since the realtype can change (e.g. in leafref), we are not able to detect
+             * which of the subtype's were tried the last time, so we have to try all of them.
+             * We also have to remove the LY_TYPE_OPTS_SECOND_CALL flag since the callbacks will be now
+             * called for the first time.
+             * In the second call we should have all the data instances, so the LY_EINCOMPLETE should not
+             * happen again.
+             */
+            options = options & ~LY_TYPE_OPTS_SECOND_CALL;
+            ly_err_free(*err);
+            *err = NULL;
+            goto search_subtype;
         }
     } else {
         /* prepare subvalue storage */
@@ -2128,12 +2138,10 @@
         /* store prefixes for later use */
         subvalue->prefixes = ly_type_get_prefixes(ctx, value, value_len, get_prefix, parser);
 
+search_subtype:
         /* use the first usable sybtype to store the value */
         LY_ARRAY_FOR(type_u->types, u) {
-            subvalue->value->plugin = type_u->types[u]->plugin;
-            subvalue->type = type_u->types[u];
-
-search_subtype:
+            subvalue->value->realtype = type_u->types[u];
             ret = type_u->types[u]->plugin->store(ctx, type_u->types[u], value, value_len, options & ~(LY_TYPE_OPTS_CANONIZE | LY_TYPE_OPTS_DYNAMIC),
                                                   ly_type_stored_prefixes_clb, subvalue->prefixes, format,
                                                   context_node, trees, subvalue->value, NULL, err);
@@ -2141,21 +2149,14 @@
                 /* success (or not yet complete) */
                 break;
             }
-
-            if (options & LY_TYPE_OPTS_SECOND_CALL) {
-                /* if started as LY_TYPE_OPTS_SECOND_CALL, we need it just for a single call of the
-                 * store callback, because if it fails, another store callback is called for the first time */
-                options = options & ~LY_TYPE_OPTS_SECOND_CALL;
-            }
-            if (*err) {
-                ly_err_free(*err);
-                *err = NULL;
-            }
+            ly_err_free(*err);
+            *err = NULL;
         }
-    }
-    if (u == LY_ARRAY_SIZE(type_u->types)) {
-        asprintf(&errmsg, "Invalid union value \"%.*s\" - no matching subtype found.", (int)value_len, value);
-        goto error;
+
+        if (u == LY_ARRAY_SIZE(type_u->types)) {
+            asprintf(&errmsg, "Invalid union value \"%.*s\" - no matching subtype found.", (int)value_len, value);
+            goto error;
+        }
     }
     /* success */
 
@@ -2199,7 +2200,7 @@
     free(subvalue->value);
     free(subvalue);
     if ((options & LY_TYPE_OPTS_SECOND_CALL) && (options & LY_TYPE_OPTS_STORE)) {
-        subvalue = NULL;
+        storage->subvalue = NULL;
     }
 
     return LY_EVALID;
@@ -2213,10 +2214,10 @@
 static LY_ERR
 ly_type_compare_union(const struct lyd_value *val1, const struct lyd_value *val2)
 {
-    if (val1->subvalue->type != val2->subvalue->type) {
+    if (val1->realtype != val2->realtype) {
         return LY_EVALID;
     }
-    return val1->subvalue->type->plugin->compare(val1->subvalue->value, val2->subvalue->value);
+    return val1->realtype->plugin->compare(val1->subvalue->value, val2->subvalue->value);
 }
 
 /**
@@ -2225,13 +2226,13 @@
  * Implementation of the ly_type_free_clb.
  */
 static void
-ly_type_free_union(struct ly_ctx *ctx, struct lysc_type *type, struct lyd_value *value)
+ly_type_free_union(struct ly_ctx *ctx, struct lyd_value *value)
 {
     unsigned int u;
 
     if (value->subvalue) {
         if (value->subvalue->value) {
-            value->subvalue->value->plugin->free(ctx, value->subvalue->type, value->subvalue->value);
+            value->subvalue->value->realtype->plugin->free(ctx, value->subvalue->value);
             LY_ARRAY_FOR(value->subvalue->prefixes, u) {
                 lydict_remove(ctx, value->subvalue->prefixes[u].prefix);
             }
@@ -2241,10 +2242,12 @@
         free(value->subvalue);
         value->subvalue = NULL;
     }
-    ly_type_free_canonical(ctx, type, value);
+    ly_type_free_canonical(ctx, value);
 }
 
-
+/**
+ * @brief Set of type plugins for YANG built-in types
+ */
 struct lysc_type_plugin ly_builtin_type_plugins[LY_DATA_TYPE_COUNT] = {
     {0}, /* LY_TYPE_UNKNOWN */
     {.type = LY_TYPE_BINARY, .store = ly_type_store_binary, .compare = ly_type_compare_canonical, .free = ly_type_free_canonical},
@@ -2267,4 +2270,3 @@
     {.type = LY_TYPE_INT32, .store = ly_type_store_int, .compare = ly_type_compare_canonical, .free = ly_type_free_canonical},
     {.type = LY_TYPE_INT64, .store = ly_type_store_int, .compare = ly_type_compare_canonical, .free = ly_type_free_canonical},
 };
-
diff --git a/src/plugins_types.h b/src/plugins_types.h
index 4b13f1f..a4b243f 100644
--- a/src/plugins_types.h
+++ b/src/plugins_types.h
@@ -137,10 +137,9 @@
  * Note that this callback is responsible also for freeing the canonized member in the @p value.
  *
  * @param[in] ctx libyang ctx to enable correct manipulation with values that are in the dictionary.
- * @param[in] type Type of the stored value.
  * @param[in,out] value Value structure to free the data stored there by the plugin's ly_type_store_clb() callback
  */
-typedef void (*ly_type_free_clb)(struct ly_ctx *ctx, struct lysc_type *type, struct lyd_value *value);
+typedef void (*ly_type_free_clb)(struct ly_ctx *ctx, struct lyd_value *value);
 
 /**
  * @brief Hold type-specific functions for various operations with the data values.
diff --git a/src/tree_data.c b/src/tree_data.c
index c9ef10f..19a3549 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -163,7 +163,9 @@
     ctx = node->schema->module->ctx;
 
     type = ((struct lysc_node_leaf*)node->schema)->type;
-    node->value.plugin = type->plugin;
+    if (!second) {
+        node->value.realtype = type;
+    }
     rc = type->plugin->store(ctx, type, value, value_len, options, get_prefix, parser, format,
                              trees ? (void*)node : (void*)node->schema, trees,
                              &node->value, NULL, &err);
@@ -286,7 +288,7 @@
     }
 
 cleanup:
-    type->plugin->free(ctx, type, &data);
+    type->plugin->free(ctx, &data);
 
     return ret;
 }
diff --git a/src/tree_data.h b/src/tree_data.h
index 242ffa1..96e0e81 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -183,7 +183,6 @@
                 const char *prefix;           /**< prefix string used in the canonized string to identify the mod of the YANG schema */
                 const struct lys_module *mod; /**< YANG schema module identified by the prefix string */
             } *prefixes;                 /**< list of mappings between prefix in canonized value to a YANG schema ([sized array](@ref sizedarrays)) */
-            struct lysc_type *type;
             struct lyd_value *value;
         } *subvalue;
 
@@ -213,10 +212,13 @@
     };  /**< The union is just a list of shorthands to possible values stored by a type's plugin. libyang works only with the canonized string,
              this specific data type storage is just to simplify use of the values by the libyang users. */
 
-    struct lysc_type_plugin *plugin; /**< pointer to the type plugin which stored the data. This pointer can differ from the pointer
-                                          in the lysc_type structure since the plugin itself can use other plugins for storing data.
-                                          Speaking about built-in types, this is the case of leafref which stores data as its target type.
-                                          Similarly union types stores the currently used type plugin in its internal lyd_value structure. */
+    struct lysc_type *realtype; /**< pointer to the real type of the data stored in the value structure. This type can differ from the type
+                                          in the schema node of the data node since the type's store plugin can use other types/plugins for
+                                          storing data. Speaking about built-in types, this is the case of leafref which stores data as its
+                                          target type. In contrast, union type also use its subtype's callbacks, but inside an internal data
+                                          lyd_value::subvalue structure, so here is the pointer to the union type.
+                                          In general, this type is used to get free callback for this lyd_value structure, so it must reflect
+                                          the type used to store data directly in the same lyd_value instance. */
 };
 
 /**
diff --git a/src/tree_data_free.c b/src/tree_data_free.c
index 36a11a0..80653d8 100644
--- a/src/tree_data_free.c
+++ b/src/tree_data_free.c
@@ -33,8 +33,7 @@
     LY_ARRAY_FOR(path, u) {
         LY_ARRAY_FOR(path[u].predicates, v) {
             if (path[u].predicates[v].type > 0) {
-                struct lysc_type *t = ((struct lysc_node_leaf*)path[u].predicates[v].key)->type;
-                t->plugin->free(ctx, t, path[u].predicates[v].value);
+                ((struct lysc_node_leaf*)path[u].predicates[v].key)->type->plugin->free(ctx, path[u].predicates[v].value);
                 free(path[u].predicates[v].value);
             }
         }
@@ -186,8 +185,7 @@
         }
 #endif
     } else if (node->schema->nodetype & LYD_NODE_TERM) {
-        struct lysc_type *type = ((struct lysc_node_leaf*)node->schema)->type;
-        type->plugin->free(ctx, type, &((struct lyd_node_term*)node)->value);
+        ((struct lysc_node_leaf*)node->schema)->type->plugin->free(ctx, &((struct lyd_node_term*)node)->value);
     }
 
     /* free the node's attributes */
diff --git a/tests/features/test_types.c b/tests/features/test_types.c
index 3da18a5..6d057d0 100644
--- a/tests/features/test_types.c
+++ b/tests/features/test_types.c
@@ -1109,7 +1109,8 @@
     leaf = (struct lyd_node_term*)tree;
     assert_string_equal("12", leaf->value.canonized);
     assert_null(leaf->value.subvalue->prefixes);
-    assert_int_equal(LY_TYPE_LEAFREF, leaf->value.subvalue->type->basetype);
+    assert_int_equal(LY_TYPE_UNION, leaf->value.realtype->basetype);
+    assert_int_equal(LY_TYPE_INT8, leaf->value.subvalue->value->realtype->basetype);
     assert_int_equal(12, leaf->value.subvalue->value->int8);
     lyd_free_all(tree);
 
@@ -1122,7 +1123,8 @@
     leaf = (struct lyd_node_term*)tree;
     assert_string_equal("2", leaf->value.canonized);
     assert_null(leaf->value.subvalue->prefixes);
-    assert_int_equal(LY_TYPE_STRING, leaf->value.subvalue->type->basetype);
+    assert_int_equal(LY_TYPE_UNION, leaf->value.realtype->basetype);
+    assert_int_equal(LY_TYPE_STRING, leaf->value.subvalue->value->realtype->basetype);
     lyd_free_all(tree);
 
     data = "<un1 xmlns=\"urn:tests:types\" xmlns:d=\"urn:tests:defs\">d:fast-ethernet</un1>";
@@ -1132,7 +1134,8 @@
     leaf = (struct lyd_node_term*)tree;
     assert_string_equal("d:fast-ethernet", leaf->value.canonized);
     assert_non_null(leaf->value.subvalue->prefixes);
-    assert_int_equal(LY_TYPE_IDENT, leaf->value.subvalue->type->basetype);
+    assert_int_equal(LY_TYPE_UNION, leaf->value.realtype->basetype);
+    assert_int_equal(LY_TYPE_IDENT, leaf->value.subvalue->value->realtype->basetype);
     assert_string_equal("fast-ethernet", leaf->value.subvalue->value->canonized);
     lyd_free_all(tree);
 
@@ -1143,7 +1146,8 @@
     leaf = (struct lyd_node_term*)tree;
     assert_string_equal("d:superfast-ethernet", leaf->value.canonized);
     assert_non_null(leaf->value.subvalue->prefixes);
-    assert_int_equal(LY_TYPE_STRING, leaf->value.subvalue->type->basetype);
+    assert_int_equal(LY_TYPE_UNION, leaf->value.realtype->basetype);
+    assert_int_equal(LY_TYPE_STRING, leaf->value.subvalue->value->realtype->basetype);
     assert_string_equal("d:superfast-ethernet", leaf->value.subvalue->value->canonized);
     lyd_free_all(tree);
 
@@ -1156,7 +1160,8 @@
     leaf = (struct lyd_node_term*)tree;
     assert_string_equal("/a:leaflisttarget[2]", leaf->value.canonized);
     assert_non_null(leaf->value.subvalue->prefixes);
-    assert_int_equal(LY_TYPE_INST, leaf->value.subvalue->type->basetype);
+    assert_int_equal(LY_TYPE_UNION, leaf->value.realtype->basetype);
+    assert_int_equal(LY_TYPE_INST, leaf->value.subvalue->value->realtype->basetype);
     assert_null(leaf->value.subvalue->value->canonized);
     lyd_free_all(tree);
 
@@ -1169,7 +1174,8 @@
     leaf = (struct lyd_node_term*)tree;
     assert_string_equal("/a:leaflisttarget[3]", leaf->value.canonized);
     assert_non_null(leaf->value.subvalue->prefixes);
-    assert_int_equal(LY_TYPE_STRING, leaf->value.subvalue->type->basetype);
+    assert_int_equal(LY_TYPE_UNION, leaf->value.realtype->basetype);
+    assert_int_equal(LY_TYPE_STRING, leaf->value.subvalue->value->realtype->basetype);
     assert_string_equal("/a:leaflisttarget[3]", leaf->value.subvalue->value->canonized);
     lyd_free_all(tree);