plugin types REFACTOR remove STORE and CANONIZE flags

The behavior was changed as if both of these
flags are always set. Also, types now always
include their canonical/JSON string value.

Finally, default value resolution was also
refactored to avoid some code duplication.
This change was most evident in deviations,
which were then significantly refactored.
diff --git a/src/diff.c b/src/diff.c
index 1ddeee4..5b75499 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -236,7 +236,6 @@
                        char **orig_value, char **key, char **orig_key)
 {
     const struct lysc_node *schema;
-    int dynamic;
     size_t buflen, bufused, first_pos, second_pos;
     struct lyd_diff_userord *userord_item;
 
@@ -307,11 +306,8 @@
     /* value */
     if ((schema->nodetype == LYS_LEAFLIST) && ((*op == LYD_DIFF_OP_REPLACE) || (*op == LYD_DIFF_OP_CREATE))) {
         if (second_pos) {
-            *value = (char *)lyd_value2str((struct lyd_node_term *)userord_item->inst[second_pos - 1], &dynamic);
-            if (!dynamic) {
-                *value = strdup(*value);
-                LY_CHECK_ERR_RET(!*value, LOGMEM(schema->module->ctx), LY_EMEM);
-            }
+            *value = strdup(LYD_CANONICAL(userord_item->inst[second_pos - 1]));
+            LY_CHECK_ERR_RET(!*value, LOGMEM(schema->module->ctx), LY_EMEM);
         } else {
             *value = strdup("");
             LY_CHECK_ERR_RET(!*value, LOGMEM(schema->module->ctx), LY_EMEM);
@@ -321,11 +317,8 @@
     /* orig-value */
     if ((schema->nodetype == LYS_LEAFLIST) && ((*op == LYD_DIFF_OP_REPLACE) || (*op == LYD_DIFF_OP_DELETE))) {
         if (first_pos) {
-            *orig_value = (char *)lyd_value2str((struct lyd_node_term *)userord_item->inst[first_pos - 1], &dynamic);
-            if (!dynamic) {
-                *orig_value = strdup(*orig_value);
-                LY_CHECK_ERR_RET(!*orig_value, LOGMEM(schema->module->ctx), LY_EMEM);
-            }
+            *orig_value = strdup(LYD_CANONICAL(userord_item->inst[first_pos - 1]));
+            LY_CHECK_ERR_RET(!*orig_value, LOGMEM(schema->module->ctx), LY_EMEM);
         } else {
             *orig_value = strdup("");
             LY_CHECK_ERR_RET(!*orig_value, LOGMEM(schema->module->ctx), LY_EMEM);
@@ -405,7 +398,6 @@
                const char **orig_default, char **orig_value)
 {
     const struct lysc_node *schema;
-    int dynamic;
 
     assert(first || second);
 
@@ -475,11 +467,8 @@
     /* orig-value */
     if ((schema->nodetype == LYS_LEAF) && (*op == LYD_DIFF_OP_REPLACE)) {
         /* leaf */
-        *orig_value = (char *)lyd_value2str((struct lyd_node_term *)first, &dynamic);
-        if (!dynamic) {
-            *orig_value = strdup(*orig_value);
-            LY_CHECK_ERR_RET(!*orig_value, LOGMEM(schema->module->ctx), LY_EMEM);
-        }
+        *orig_value = strdup(LYD_CANONICAL(first));
+        LY_CHECK_ERR_RET(!*orig_value, LOGMEM(schema->module->ctx), LY_EMEM);
     }
 
     return LY_SUCCESS;
@@ -748,13 +737,11 @@
     struct lyd_meta *meta = NULL;
     const struct lyd_node *diff_parent;
     const char *str;
-    int dynamic;
 
     for (diff_parent = diff_node; diff_parent; diff_parent = (struct lyd_node *)diff_parent->parent) {
         LY_LIST_FOR(diff_parent->meta, meta) {
             if (!strcmp(meta->name, "operation") && !strcmp(meta->annotation->module->name, "yang")) {
-                str = lyd_meta2str(meta, &dynamic);
-                assert(!dynamic);
+                str = meta->value.canonical;
                 if ((str[0] == 'r') && (diff_parent != diff_node)) {
                     /* we do not care about this operation if it's in our parent */
                     continue;
@@ -871,7 +858,6 @@
     const char *str_val;
     enum lyd_diff_op op;
     struct lyd_meta *meta;
-    int dynamic;
     const struct ly_ctx *ctx = LYD_NODE_CTX(diff_node);
 
     /* read all the valid attributes */
@@ -890,7 +876,7 @@
         /* get "key" or "value" metadata string value */
         meta = lyd_find_meta(diff_node->meta, NULL, diff_node->schema->nodetype == LYS_LIST ? "yang:key" : "yang:value");
         LY_CHECK_ERR_RET(!meta, LOGINT(LYD_NODE_CTX(diff_node)), LY_EINT);
-        str_val = lyd_meta2str(meta, &dynamic);
+        str_val = meta->value.canonical;
 
         /* insert/move the node */
         if (str_val[0]) {
@@ -898,9 +884,6 @@
         } else {
             ret = lyd_diff_insert(first_node, parent_node, match, NULL);
         }
-        if (dynamic) {
-            free((char *)str_val);
-        }
         if (ret) {
             if (op == LYD_DIFF_OP_CREATE) {
                 lyd_free_tree(match);
@@ -969,11 +952,7 @@
         lyd_diff_find_node(*first_node, diff_node, &match);
 
         /* update its value */
-        str_val = lyd_value2str((struct lyd_node_term *)diff_node, &dynamic);
-        ret = lyd_change_term(match, str_val);
-        if (dynamic) {
-            free((char *)str_val);
-        }
+        ret = lyd_change_term(match, LYD_CANONICAL(diff_node));
         if (ret && (ret != LY_EEXIST)) {
             LOGINT_RET(ctx);
         }
@@ -1108,7 +1087,6 @@
 lyd_diff_merge_replace(struct lyd_node *diff_match, enum lyd_diff_op cur_op, const struct lyd_node *src_diff)
 {
     LY_ERR ret;
-    int dynamic;
     const char *str_val, *meta_name;
     struct lyd_meta *meta;
     const struct lys_module *mod;
@@ -1140,26 +1118,16 @@
                 LOGINT_RET(LYD_NODE_CTX(src_diff));
             }
 
-            /* get leaf value */
-            str_val = lyd_value2str((struct lyd_node_term *)src_diff, &dynamic);
-
             /* modify the node value */
-            ret = lyd_change_term(diff_match, str_val);
-            if (dynamic) {
-                free((char *)str_val);
-            }
-            if (ret) {
+            if (lyd_change_term(diff_match, LYD_CANONICAL(src_diff))) {
                 LOGINT_RET(LYD_NODE_CTX(src_diff));
             }
 
             /* compare values whether there is any change at all */
             meta = lyd_find_meta(diff_match->meta, mod, "orig-value");
             LY_CHECK_ERR_RET(!meta, LOGINT(LYD_NODE_CTX(diff_match)), LY_EINT);
-            str_val = lyd_meta2str(meta, &dynamic);
+            str_val = meta->value.canonical;
             ret = lyd_value_compare((struct lyd_node_term *)diff_match, str_val, strlen(str_val), NULL);
-            if (dynamic) {
-                free((char *)str_val);
-            }
             if (!ret) {
                 /* values are the same, remove orig-value meta and set oper to NONE */
                 lyd_free_meta_single(meta);
@@ -1222,9 +1190,6 @@
 {
     struct lyd_node *child;
     const struct lysc_node_leaf *sleaf;
-    const char *str_val;
-    int dynamic;
-    LY_ERR ret;
 
     switch (cur_op) {
     case LYD_DIFF_OP_DELETE:
@@ -1261,20 +1226,10 @@
 
         if (lyd_compare_single(diff_match, src_diff, 0)) {
             /* current value is the previous one (meta) */
-            str_val = lyd_value2str((struct lyd_node_term *)diff_match, &dynamic);
-            ret = lyd_new_meta(diff_match, NULL, "yang:orig-value", str_val, NULL);
-            if (dynamic) {
-                free((char *)str_val);
-            }
-            LY_CHECK_RET(ret);
+            LY_CHECK_RET(lyd_new_meta(diff_match, NULL, "yang:orig-value", LYD_CANONICAL(diff_match), NULL));
 
             /* update the value itself */
-            str_val = lyd_value2str((struct lyd_node_term *)src_diff, &dynamic);
-            ret = lyd_change_term(diff_match, str_val);
-            if (dynamic) {
-                free((char *)str_val);
-            }
-            LY_CHECK_RET(ret);
+            LY_CHECK_RET(lyd_change_term(diff_match, LYD_CANONICAL(src_diff)));
         }
 
         if (diff_match->schema->nodetype & LYD_NODE_TERM) {
@@ -1365,7 +1320,6 @@
     struct lyd_node *child;
     const struct lys_module *mod;
     const char *str;
-    int dynamic;
 
     assert(diff);
 
@@ -1405,8 +1359,7 @@
         /* check whether at least the default flags are different */
         meta = lyd_find_meta(diff->meta, mod, "orig-default");
         assert(meta);
-        str = lyd_meta2str(meta, &dynamic);
-        assert(!dynamic);
+        str = meta->value.canonical;
 
         /* if previous and current dflt flags are the same, this node is redundant */
         if ((!strcmp(str, "true") && (diff->flags & LYD_DEFAULT)) || (!strcmp(str, "false") && !(diff->flags & LYD_DEFAULT))) {
@@ -1557,17 +1510,18 @@
 {
     LY_ERR ret = LY_SUCCESS;
     struct lyd_meta *meta;
-    const char *val1 = NULL, *val2 = NULL;
-    int dyn1 = 0, dyn2 = 0, flags;
+    const char *val1 = NULL;
+    char *val2;
+    int flags;
 
     meta = lyd_find_meta(leaf->meta, mod, "orig-value");
     LY_CHECK_ERR_RET(!meta, LOGINT(LYD_NODE_CTX(leaf)), LY_EINT);
 
     /* orig-value */
-    val1 = lyd_meta2str(meta, &dyn1);
+    val1 = meta->value.canonical;
 
     /* current value */
-    val2 = lyd_value2str((struct lyd_node_term *)leaf, &dyn2);
+    val2 = strdup(LYD_CANONICAL(leaf));
 
     /* switch values, keep default flag */
     flags = leaf->flags;
@@ -1576,12 +1530,7 @@
     LY_CHECK_GOTO(ret = lyd_change_meta(meta, val2), cleanup);
 
 cleanup:
-    if (dyn1) {
-        free((char *)val1);
-    }
-    if (dyn2) {
-        free((char *)val2);
-    }
+    free(val2);
     return ret;
 }
 
@@ -1589,8 +1538,7 @@
 lyd_diff_reverse_default(struct lyd_node *node, const struct lys_module *mod)
 {
     struct lyd_meta *meta;
-    const char *val;
-    int dyn, flag1, flag2;
+    int flag1, flag2;
 
     meta = lyd_find_meta(node->meta, mod, "orig-default");
     if (!meta) {
@@ -1599,9 +1547,7 @@
     }
 
     /* orig-default */
-    val = lyd_meta2str(meta, &dyn);
-    assert(!dyn);
-    if (!strcmp(val, "true")) {
+    if (meta->value.boolean) {
         flag1 = LYD_DEFAULT;
     } else {
         flag1 = 0;
@@ -1623,8 +1569,8 @@
 {
     LY_ERR ret = LY_SUCCESS;
     struct lyd_meta *meta1, *meta2;
-    const char *val1 = NULL, *val2 = NULL;
-    int dyn1 = 0, dyn2 = 0;
+    const char *val1 = NULL;
+    char *val2 = NULL;
 
     meta1 = lyd_find_meta(node->meta, mod, name1);
     LY_CHECK_ERR_RET(!meta1, LOGINT(LYD_NODE_CTX(node)), LY_EINT);
@@ -1633,22 +1579,17 @@
     LY_CHECK_ERR_RET(!meta2, LOGINT(LYD_NODE_CTX(node)), LY_EINT);
 
     /* value1 */
-    val1 = lyd_meta2str(meta1, &dyn1);
+    val1 = meta1->value.canonical;
 
     /* value2 */
-    val2 = lyd_meta2str(meta2, &dyn2);
+    val2 = strdup(meta2->value.canonical);
 
     /* switch values */
     LY_CHECK_GOTO(ret = lyd_change_meta(meta1, val2), cleanup);
     LY_CHECK_GOTO(ret = lyd_change_meta(meta2, val1), cleanup);
 
 cleanup:
-    if (dyn1) {
-        free((char *)val1);
-    }
-    if (dyn2) {
-        free((char *)val2);
-    }
+    free(val2);
     return ret;
 }
 
diff --git a/src/path.c b/src/path.c
index c2dad18..09ccaf6 100644
--- a/src/path.c
+++ b/src/path.c
@@ -947,7 +947,6 @@
                 case LY_PATH_PREDTYPE_LEAFLIST:
                     /* key-predicate or leaf-list-predicate */
                     (*dup)[u].predicates[v].key = pred->key;
-                    (*dup)[u].predicates[v].value.realtype = pred->value.realtype;
                     pred->value.realtype->plugin->duplicate(ctx, &pred->value, &(*dup)[u].predicates[v].value);
                     break;
                 case LY_PATH_PREDTYPE_NONE:
diff --git a/src/plugins_types.c b/src/plugins_types.c
index 779a85e..319875d 100644
--- a/src/plugins_types.c
+++ b/src/plugins_types.c
@@ -159,9 +159,9 @@
  * Implementation of the ly_type_compare_clb.
  */
 static LY_ERR
-ly_type_compare_canonical(const struct lyd_value *val1, const struct lyd_value *val2)
+ly_type_compare_simple(const struct lyd_value *val1, const struct lyd_value *val2)
 {
-    if (val1 == val2 || !strcmp(val1->canonical_cache, val2->canonical_cache)) {
+    if ((val1->realtype == val2->realtype) && (val1->canonical == val2->canonical)) {
         return LY_SUCCESS;
     }
 
@@ -174,28 +174,11 @@
  * Implementation of the ly_type_print_clb.
  */
 static const char *
-ly_type_print_canonical(const struct lyd_value *value, LY_PREFIX_FORMAT UNUSED(format),
+ly_type_print_simple(const struct lyd_value *value, LY_PREFIX_FORMAT UNUSED(format),
                         void *UNUSED(prefix_data), int *dynamic)
 {
     *dynamic = 0;
-    return (char *)value->canonical_cache;
-}
-
-/**
- * @brief Generic duplication callback of the original value only.
- *
- * Implementation of the ly_type_dup_clb.
- */
-static LY_ERR
-ly_type_dup_original(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
-{
-    dup->canonical_cache = original->canonical_cache;
-    dup->original = (void*)lydict_insert(ctx, original->original, strlen(original->original));
-    if (dup->original) {
-        return LY_SUCCESS;
-    } else {
-        return LY_EINT;
-    }
+    return (char *)value->canonical;
 }
 
 /**
@@ -204,27 +187,12 @@
  * Implementation of the ly_type_dup_clb.
  */
 static LY_ERR
-ly_type_dup_canonical(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
+ly_type_dup_simple(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
 {
-    ly_type_dup_original(ctx, original, dup);
-    dup->canonical_cache = (void*)lydict_insert(ctx, original->canonical_cache, strlen(original->canonical_cache));
-    if (dup->canonical_cache) {
-        return LY_SUCCESS;
-    } else {
-        return LY_EINT;
-    }
-}
-
-/**
- * @brief Free original value in lyd_value.
- *
- * Implementation of the ly_type_free_clb.
- */
-static void
-ly_type_free_original(const struct ly_ctx *ctx, struct lyd_value *value)
-{
-    lydict_remove(ctx, value->original);
-    value->original = NULL;
+    dup->canonical = lydict_insert(ctx, original->canonical, strlen(original->canonical));
+    dup->ptr = original->ptr;
+    dup->realtype = original->realtype;
+    return LY_SUCCESS;
 }
 
 /**
@@ -233,11 +201,10 @@
  * Implementation of the ly_type_free_clb.
  */
 static void
-ly_type_free_canonical(const struct ly_ctx *ctx, struct lyd_value *value)
+ly_type_free_simple(const struct ly_ctx *ctx, struct lyd_value *value)
 {
-    ly_type_free_original(ctx, value);
-    lydict_remove(ctx, value->canonical_cache);
-    value->canonical_cache = NULL;
+    lydict_remove(ctx, value->canonical);
+    value->canonical = NULL;
 }
 
 API LY_ERR
@@ -545,40 +512,6 @@
     }
 }
 
-static void
-ly_type_store_strval(const struct ly_ctx *ctx, int options, const char *orig, const char *value,
-                     struct lyd_value *storage, const char **canonized)
-{
-    if (options & LY_TYPE_OPTS_CANONIZE) {
-        *canonized = value;
-    }
-    if (options & LY_TYPE_OPTS_STORE) {
-        storage->original = orig;
-        if (options & LY_TYPE_OPTS_CANONIZE) {
-            /* already stored outside the storage in canonized, so we have to add instance in dictionary */
-            storage->canonical_cache = (void*)lydict_insert(ctx, value, strlen(value));
-        } else {
-            storage->canonical_cache = (void*)value;
-        }
-    }
-}
-#if 0
-static void
-ly_type_store_canonized(const struct ly_ctx *ctx, int options, const char *value, struct lyd_value *storage, const char **canonized)
-{
-    if (options & LY_TYPE_OPTS_CANONIZE) {
-        *canonized = value;
-    }
-    if (options & LY_TYPE_OPTS_STORE) {
-        if (options & LY_TYPE_OPTS_CANONIZE) {
-            /* already stored outside the storage in canonized, so we have to add instance in dictionary */
-            storage->canonical_cache = (void*)lydict_insert(ctx, value, strlen(value));
-        } else {
-            storage->canonical_cache = (void*)value;
-        }
-    }
-}
-#endif
 /**
  * @brief Validate, canonize and store value of the YANG built-in signed integer types.
  *
@@ -587,11 +520,10 @@
 static LY_ERR
 ly_type_store_int(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
                   LY_PREFIX_FORMAT UNUSED(format), void *UNUSED(prefix_data), const void *UNUSED(context_node),
-                  const struct lyd_node *UNUSED(tree), struct lyd_value *storage, const char **canonized,
-                  struct ly_err_item **err)
+                  const struct lyd_node *UNUSED(tree), struct lyd_value *storage, struct ly_err_item **err)
 {
     LY_ERR ret;
-    int64_t i;
+    int64_t num;
     char *str;
     struct lysc_type_num *type_num = (struct lysc_type_num *)type;
 
@@ -601,59 +533,41 @@
 
     switch (type->basetype) {
     case LY_TYPE_INT8:
-        LY_CHECK_RET(ly_type_parse_int("int8", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10, INT64_C(-128), INT64_C(127), value, value_len, &i, err));
+        LY_CHECK_RET(ly_type_parse_int("int8", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10, INT64_C(-128), INT64_C(127), value, value_len, &num, err));
         break;
     case LY_TYPE_INT16:
-        LY_CHECK_RET(ly_type_parse_int("int16", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10, INT64_C(-32768), INT64_C(32767), value, value_len, &i, err));
+        LY_CHECK_RET(ly_type_parse_int("int16", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10, INT64_C(-32768), INT64_C(32767), value, value_len, &num, err));
         break;
     case LY_TYPE_INT32:
         LY_CHECK_RET(ly_type_parse_int("int32", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10,
-                                       INT64_C(-2147483648), INT64_C(2147483647), value, value_len, &i, err));
+                                       INT64_C(-2147483648), INT64_C(2147483647), value, value_len, &num, err));
         break;
     case LY_TYPE_INT64:
         LY_CHECK_RET(ly_type_parse_int("int64", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10,
-                                       INT64_C(-9223372036854775807) - INT64_C(1), INT64_C(9223372036854775807), value, value_len, &i, err));
+                                       INT64_C(-9223372036854775807) - INT64_C(1), INT64_C(9223372036854775807), value, value_len, &num, err));
         break;
     default:
-        LOGINT_RET(NULL);
+        LOGINT_RET(ctx);
     }
 
-    LY_CHECK_RET(asprintf(&str, "%"PRId64, i) == -1, LY_EMEM);
+    LY_CHECK_RET(asprintf(&str, "%"PRId64, num) == -1, LY_EMEM);
 
     /* range of the number */
     if (type_num->range) {
-        LY_CHECK_ERR_RET(ret = ly_type_validate_range(type->basetype, type_num->range, i, str, err), free(str), ret);
+        LY_CHECK_ERR_RET(ret = ly_type_validate_range(type->basetype, type_num->range, num, str, err), free(str), ret);
     }
 
-    if (options & (LY_TYPE_OPTS_CANONIZE | LY_TYPE_OPTS_STORE)) {
-        if (options & LY_TYPE_OPTS_STORE) {
-            storage->int64 = i;
-            ly_type_store_strval(ctx, options, lydict_insert(ctx, value_len ? value : "", value_len),
-                                 lydict_insert_zc(ctx, str), storage, canonized);
-        } else {
-            ly_type_store_strval(ctx, options, NULL, lydict_insert_zc(ctx, str), storage, canonized);
-        }
-        str = NULL;
-    }
-    free(str);
+    /* store everything */
+    storage->canonical = lydict_insert_zc(ctx, str);
+    storage->int64 = num;
+    storage->realtype = type;
+
     if (options & LY_TYPE_OPTS_DYNAMIC) {
-        free((char*)value);
+        free((char *)value);
     }
-
     return LY_SUCCESS;
 }
 
-/* @brief Duplication callback of the signed integer values.
- *
- * Implementation of the ly_type_dup_clb.
- */
-static LY_ERR
-ly_type_dup_int(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
-{
-    dup->int64 = original->int64;
-    return ly_type_dup_canonical(ctx, original, dup);
-}
-
 /**
  * @brief Validate and canonize value of the YANG built-in unsigned integer types.
  *
@@ -662,11 +576,10 @@
 static LY_ERR
 ly_type_store_uint(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
                    LY_PREFIX_FORMAT UNUSED(format), void *UNUSED(prefix_data), const void *UNUSED(context_node),
-                   const struct lyd_node *UNUSED(tree), struct lyd_value *storage, const char **canonized,
-                   struct ly_err_item **err)
+                   const struct lyd_node *UNUSED(tree), struct lyd_value *storage, struct ly_err_item **err)
 {
     LY_ERR ret;
-    uint64_t u;
+    uint64_t num;
     struct lysc_type_num* type_num = (struct lysc_type_num*)type;
     char *str;
 
@@ -676,59 +589,40 @@
 
     switch (type->basetype) {
     case LY_TYPE_UINT8:
-        LY_CHECK_RET(ly_type_parse_uint("uint8", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10, UINT64_C(255), value, value_len, &u, err));
+        LY_CHECK_RET(ly_type_parse_uint("uint8", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10, UINT64_C(255), value, value_len, &num, err));
         break;
     case LY_TYPE_UINT16:
-        LY_CHECK_RET(ly_type_parse_uint("uint16", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10, UINT64_C(65535), value, value_len, &u, err));
+        LY_CHECK_RET(ly_type_parse_uint("uint16", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10, UINT64_C(65535), value, value_len, &num, err));
         break;
     case LY_TYPE_UINT32:
-        LY_CHECK_RET(ly_type_parse_uint("uint32", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10, UINT64_C(4294967295), value, value_len, &u, err));
+        LY_CHECK_RET(ly_type_parse_uint("uint32", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10, UINT64_C(4294967295), value, value_len, &num, err));
         break;
     case LY_TYPE_UINT64:
-        LY_CHECK_RET(ly_type_parse_uint("uint64", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10, UINT64_C(18446744073709551615), value, value_len, &u, err));
+        LY_CHECK_RET(ly_type_parse_uint("uint64", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10, UINT64_C(18446744073709551615), value, value_len, &num, err));
         break;
     default:
-        LOGINT_RET(NULL);
+        LOGINT_RET(ctx);
     }
 
-    LY_CHECK_RET(asprintf(&str, "%"PRIu64, u) == -1, LY_EMEM);
+    LY_CHECK_RET(asprintf(&str, "%"PRIu64, num) == -1, LY_EMEM);
 
     /* range of the number */
     if (type_num->range) {
-        LY_CHECK_ERR_RET(ret = ly_type_validate_range(type->basetype, type_num->range, u, str, err), free(str), ret);
+        LY_CHECK_ERR_RET(ret = ly_type_validate_range(type->basetype, type_num->range, num, str, err), free(str), ret);
     }
 
-    if (options & (LY_TYPE_OPTS_CANONIZE | LY_TYPE_OPTS_STORE)) {
-        if (options & LY_TYPE_OPTS_STORE) {
-            storage->int64 = u;
-            ly_type_store_strval(ctx, options, lydict_insert(ctx, value_len ? value : "", value_len),
-                                 lydict_insert_zc(ctx, str), storage, canonized);
-        } else {
-            ly_type_store_strval(ctx, options, NULL, lydict_insert_zc(ctx, str), storage, canonized);
-        }
-        str = NULL;
-    }
-    free(str);
+    /* store everything */
+    storage->canonical = lydict_insert_zc(ctx, str);
+    storage->int64 = num;
+    storage->realtype = type;
+
     if (options & LY_TYPE_OPTS_DYNAMIC) {
-        free((char*)value);
+        free((char *)value);
     }
-
     return LY_SUCCESS;
 }
 
 /**
- * @brief Duplication callback of the unsigned integer values.
- *
- * Implementation of the ly_type_dup_clb.
- */
-static LY_ERR
-ly_type_dup_uint(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
-{
-    dup->uint64 = original->uint64;
-    return ly_type_dup_canonical(ctx, original, dup);
-}
-
-/**
  * @brief Validate, canonize and store value of the YANG built-in decimal64 types.
  *
  * Implementation of the ly_type_store_clb.
@@ -736,8 +630,7 @@
 static LY_ERR
 ly_type_store_decimal64(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
                         LY_PREFIX_FORMAT UNUSED(format), void *UNUSED(prefix_data), const void *UNUSED(context_node),
-                        const struct lyd_node *UNUSED(tree), struct lyd_value *storage, const char **canonized,
-                        struct ly_err_item **err)
+                        const struct lyd_node *UNUSED(tree), struct lyd_value *storage, struct ly_err_item **err)
 {
     int64_t d;
     struct lysc_type_dec* type_dec = (struct lysc_type_dec*)type;
@@ -785,33 +678,16 @@
         LY_CHECK_RET(ly_type_validate_range(type->basetype, type_dec->range, d, buf, err));
     }
 
-    if (options & (LY_TYPE_OPTS_CANONIZE | LY_TYPE_OPTS_STORE)) {
-        if (options & LY_TYPE_OPTS_STORE) {
-            storage->dec64 = d;
-            ly_type_store_strval(ctx, options, lydict_insert(ctx, value, value_len),
-                                 lydict_insert(ctx, buf, strlen(buf)), storage, canonized);
-        } else {
-            ly_type_store_strval(ctx, options, NULL, lydict_insert(ctx, buf, strlen(buf)), storage, canonized);
-        }
-    }
+    storage->canonical = lydict_insert(ctx, buf, strlen(buf));
+    storage->dec64 = d;
+    storage->realtype = type;
+
     if (options & LY_TYPE_OPTS_DYNAMIC) {
-        free((char*)value);
+        free((char *)value);
     }
-
     return LY_SUCCESS;
 }
 
-/* @brief Duplication callback of the decimal64 values.
- *
- * Implementation of the ly_type_dup_clb.
- */
-static LY_ERR
-ly_type_dup_decimal64(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
-{
-   dup->dec64 = original->dec64;
-   return ly_type_dup_canonical(ctx, original, dup);
-}
-
 /**
  * @brief Validate, canonize and store value of the YANG built-in binary type.
  *
@@ -820,8 +696,7 @@
 static LY_ERR
 ly_type_store_binary(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
                      LY_PREFIX_FORMAT UNUSED(format), void *UNUSED(prefix_data), const void *UNUSED(context_node),
-                     const struct lyd_node *UNUSED(tree), struct lyd_value *storage, const char **canonized,
-                     struct ly_err_item **err)
+                     const struct lyd_node *UNUSED(tree), struct lyd_value *storage, struct ly_err_item **err)
 {
     size_t start = 0, stop = 0, count = 0, u, termination = 0;
     struct lysc_type_bin *type_bin = (struct lysc_type_bin *)type;
@@ -892,23 +767,17 @@
         LY_CHECK_RET(ly_type_validate_range(LY_TYPE_BINARY, type_bin->length, len, buf, err));
     }
 
-    if (options & (LY_TYPE_OPTS_CANONIZE | LY_TYPE_OPTS_STORE)) {
-        const char *c;
-        if (start != 0 || (value_len && stop != value_len - 1)) {
-            c = lydict_insert_zc(ctx, strndup(&value[start], stop + 1 - start));
-        } else {
-            c = lydict_insert(ctx, value_len ? value : "", value_len);
-        }
-        if (options & LY_TYPE_OPTS_STORE) {
-            ly_type_store_strval(ctx, options, lydict_insert(ctx, value_len ? value : "", value_len), c, storage, canonized);
-        } else {
-            ly_type_store_strval(ctx, options, NULL, c, storage, canonized);
-        }
+    if (start != 0 || (value_len && stop != value_len - 1)) {
+        storage->canonical = lydict_insert(ctx, &value[start], stop + 1 - start);
+    } else {
+        storage->canonical = lydict_insert(ctx, value_len ? value : "", value_len);
     }
-    if (options & LY_TYPE_OPTS_DYNAMIC) {
-        free((char*)value);
-    }
+    storage->ptr = NULL;
+    storage->realtype = type;
 
+    if (options & LY_TYPE_OPTS_DYNAMIC) {
+        free((char *)value);
+    }
     return LY_SUCCESS;
 
 error:
@@ -930,8 +799,7 @@
 static LY_ERR
 ly_type_store_string(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
                      LY_PREFIX_FORMAT UNUSED(format), void *UNUSED(prefix_data), const void *UNUSED(context_node),
-                     const struct lyd_node *UNUSED(tree), struct lyd_value *storage, const char **canonized,
-                     struct ly_err_item **err)
+                     const struct lyd_node *UNUSED(tree), struct lyd_value *storage, struct ly_err_item **err)
 {
     struct lysc_type_str *type_str = (struct lysc_type_str *)type;
 
@@ -952,16 +820,13 @@
     /* pattern restrictions */
     LY_CHECK_RET(ly_type_validate_patterns(type_str->patterns, value, value_len, err));
 
-    if (options & (LY_TYPE_OPTS_CANONIZE | LY_TYPE_OPTS_STORE)) {
-        /* NOTE: despite the pointer is used in storage twice (original and canonical_cache), it is stored in dictionary
-         * just once. This works even without storage - the string is returned as canonized. In case both options are used,
-         * ly_type_store_strval() increases reference count in dictionary for canonized. */
-        const char *str = lydict_insert(ctx, value_len ? value : "", value_len);
-        ly_type_store_strval(ctx, options, str, str, storage, canonized);
-    }
     if (options & LY_TYPE_OPTS_DYNAMIC) {
-        free((char*)value);
+        storage->canonical = lydict_insert_zc(ctx, value_len ? (char *)value : "");
+    } else {
+        storage->canonical = lydict_insert(ctx, value_len ? value : "", value_len);
     }
+    storage->ptr = NULL;
+    storage->realtype = type;
 
     return LY_SUCCESS;
 }
@@ -974,8 +839,7 @@
 static LY_ERR
 ly_type_store_bits(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
                    LY_PREFIX_FORMAT UNUSED(format), void *UNUSED(prefix_data), const void *UNUSED(context_node),
-                   const struct lyd_node *UNUSED(tree), struct lyd_value *storage, const char **canonized,
-                   struct ly_err_item **err)
+                   const struct lyd_node *UNUSED(tree), struct lyd_value *storage, struct ly_err_item **err)
 {
     LY_ERR ret = LY_EVALID;
     size_t item_len;
@@ -1051,63 +915,62 @@
     }
     /* validation done */
 
-    if (options & (LY_TYPE_OPTS_CANONIZE | LY_TYPE_OPTS_STORE)) {
-        if (iscanonical) {
-            /* items are already ordered */
-            items_ordered = items;
-            items = NULL;
+    if (iscanonical) {
+        /* items are already ordered */
+        items_ordered = items;
+        items = NULL;
 
-            if (!ws_count && !lws_count && (options & LY_TYPE_OPTS_DYNAMIC)) {
-                can = lydict_insert_zc(ctx, (char*)value);
-                value = NULL;
-            } else {
-                can = lydict_insert(ctx, value_len ? &value[lws_count] : "", value_len - ws_count - lws_count);
-            }
+        if (!ws_count && !lws_count && (options & LY_TYPE_OPTS_DYNAMIC)) {
+            can = lydict_insert_zc(ctx, (char *)value);
+            value = NULL;
+            options &= ~LY_TYPE_OPTS_DYNAMIC;
         } else {
-            buf = malloc(buf_size * sizeof *buf);
-            LY_CHECK_ERR_GOTO(!buf, LOGMEM(ctx); ret = LY_EMEM, error);
-            index = 0;
-
-            items_ordered = ly_set_dup(items, NULL);
-            LY_CHECK_ERR_GOTO(!items_ordered, LOGMEM(ctx); ret = LY_EMEM, error);
-            items_ordered->count = 0;
-
-            /* generate ordered bits list */
-            LY_ARRAY_FOR(type_bits->bits, u) {
-                if (ly_set_contains(items, &type_bits->bits[u]) != -1) {
-                    int c = sprintf(&buf[index], "%s%s", index ? " " : "", type_bits->bits[u].name);
-                    LY_CHECK_ERR_GOTO(c < 0, LOGERR(ctx, LY_ESYS, "sprintf() failed."); ret = LY_ESYS, error);
-                    index += c;
-                    ly_set_add(items_ordered, &type_bits->bits[u], LY_SET_OPT_USEASLIST);
-                }
-            }
-            assert(buf_size == index + 1);
-            /* termination NULL-byte */
-            buf[index] = '\0';
-
-            can = lydict_insert_zc(ctx, buf);
-            buf = NULL;
+            can = lydict_insert(ctx, value_len ? &value[lws_count] : "", value_len - ws_count - lws_count);
         }
+    } else {
+        buf = malloc(buf_size * sizeof *buf);
+        LY_CHECK_ERR_GOTO(!buf, LOGMEM(ctx); ret = LY_EMEM, error);
+        index = 0;
 
-        ly_type_store_strval(ctx, options, lydict_insert(ctx, value_len ? value : "", value_len), can, storage, canonized);
+        items_ordered = ly_set_dup(items, NULL);
+        LY_CHECK_ERR_GOTO(!items_ordered, LOGMEM(ctx); ret = LY_EMEM, error);
+        items_ordered->count = 0;
 
-        if (options & LY_TYPE_OPTS_STORE) {
-            /* store data */
-            LY_ARRAY_CREATE_GOTO(ctx, storage->bits_items, items_ordered->count, ret, error);
-            for (uint32_t x = 0; x < items_ordered->count; x++) {
-                storage->bits_items[x] = items_ordered->objs[x];
-                LY_ARRAY_INCREMENT(storage->bits_items);
+        /* generate ordered bits list */
+        LY_ARRAY_FOR(type_bits->bits, u) {
+            if (ly_set_contains(items, &type_bits->bits[u]) != -1) {
+                int c = sprintf(&buf[index], "%s%s", index ? " " : "", type_bits->bits[u].name);
+                LY_CHECK_ERR_GOTO(c < 0, LOGERR(ctx, LY_ESYS, "sprintf() failed."); ret = LY_ESYS, error);
+                index += c;
+                ly_set_add(items_ordered, &type_bits->bits[u], LY_SET_OPT_USEASLIST);
             }
         }
-        ly_set_free(items_ordered, NULL);
+        assert(buf_size == index + 1);
+        /* termination NULL-byte */
+        buf[index] = '\0';
+
+        can = lydict_insert_zc(ctx, buf);
+        buf = NULL;
     }
 
+    /* store all data */
+    storage->canonical = can;
+    can = NULL;
+    LY_ARRAY_CREATE_GOTO(ctx, storage->bits_items, items_ordered->count, ret, error);
+    for (uint32_t x = 0; x < items_ordered->count; x++) {
+        storage->bits_items[x] = items_ordered->objs[x];
+        LY_ARRAY_INCREMENT(storage->bits_items);
+    }
+    ly_set_free(items_ordered, NULL);
+    storage->realtype = type;
+
     if (options & LY_TYPE_OPTS_DYNAMIC) {
-        free((char*)value);
+        free((char *)value);
     }
 
     ly_set_free(items, NULL);
     return LY_SUCCESS;
+
 error:
     if (erc == -1) {
         *err = ly_err_new(LY_LLERR, LY_EMEM, 0, "Memory allocation failed.", NULL, NULL);
@@ -1137,7 +1000,9 @@
         dup->bits_items[u] = original->bits_items[u];
     }
 
-   return ly_type_dup_canonical(ctx, original, dup);
+    dup->canonical = lydict_insert(ctx, original->canonical, strlen(original->canonical));
+    dup->realtype = original->realtype;
+    return LY_SUCCESS;
 }
 
 /**
@@ -1151,10 +1016,10 @@
     LY_ARRAY_FREE(value->bits_items);
     value->bits_items = NULL;
 
-    ly_type_free_canonical(ctx, value);
+    lydict_remove(ctx, value->canonical);
+    value->canonical = NULL;
 }
 
-
 /**
  * @brief Validate, canonize and store value of the YANG built-in enumeration type.
  *
@@ -1163,8 +1028,7 @@
 static LY_ERR
 ly_type_store_enum(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
                    LY_PREFIX_FORMAT UNUSED(format), void *UNUSED(prefix_data), const void *UNUSED(context_node),
-                   const struct lyd_node *UNUSED(tree), struct lyd_value *storage, const char **canonized,
-                   struct ly_err_item **err)
+                   const struct lyd_node *UNUSED(tree), struct lyd_value *storage, struct ly_err_item **err)
 {
     LY_ARRAY_COUNT_TYPE u, v;
     char *errmsg = NULL;
@@ -1198,19 +1062,13 @@
 match:
     /* validation done */
 
-    if (options & (LY_TYPE_OPTS_CANONIZE | LY_TYPE_OPTS_STORE)) {
-        /* NOTE: despite the pointer is used in storage twice (original and canonical_cache), it is stored in dictionary
-         * just once. This works even without storage - the string is returned as canonized. In case both options are used,
-         * ly_type_store_strval() increases reference count in dictionary for canonized. */
-        const char *str = lydict_insert(ctx, value_len ? value : "", value_len);
-        if (options & LY_TYPE_OPTS_STORE) {
-            storage->enum_item = &type_enum->enums[u];
-        }
-        ly_type_store_strval(ctx, options, str, str, storage, canonized);
-    }
     if (options & LY_TYPE_OPTS_DYNAMIC) {
-        free((char*)value);
+        storage->canonical = lydict_insert_zc(ctx, (char *)value);
+    } else {
+        storage->canonical = lydict_insert(ctx, value_len ? value : "", value_len);
     }
+    storage->enum_item = &type_enum->enums[u];
+    storage->realtype = type;
 
     return LY_SUCCESS;
 
@@ -1224,27 +1082,16 @@
     }
 }
 
-/* @brief Duplication callback of the enumeration values.
- *
- * Implementation of the ly_type_dup_clb.
- */
-static LY_ERR
-ly_type_dup_enum(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
-{
-    dup->enum_item = original->enum_item;
-    return ly_type_dup_original(ctx, original, dup);
-}
-
 /**
  * @brief Validate and store value of the YANG built-in boolean type.
  *
  * Implementation of the ly_type_store_clb.
  */
 static LY_ERR
-ly_type_store_boolean(const struct ly_ctx *ctx, struct lysc_type *UNUSED(type), const char *value, size_t value_len,
+ly_type_store_boolean(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len,
                       int options, LY_PREFIX_FORMAT UNUSED(format), void *UNUSED(prefix_data),
                       const void *UNUSED(context_node), const struct lyd_node *UNUSED(tree),
-                      struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
+                      struct lyd_value *storage, struct ly_err_item **err)
 {
     int8_t i;
 
@@ -1267,44 +1114,27 @@
         }
     }
 
-    if (options & (LY_TYPE_OPTS_CANONIZE | LY_TYPE_OPTS_STORE)) {
-        /* NOTE: despite the pointer is used in storage twice (original and canonical_cache), it is stored in dictionary
-         * just once. This works even without storage - the string is returned as canonized. In case both options are used,
-         * ly_type_store_strval() increases reference count in dictionary for canonized. */
-        const char *str = lydict_insert(ctx, value, value_len);
-        if (options & LY_TYPE_OPTS_STORE) {
-            storage->boolean = i;
-        }
-        ly_type_store_strval(ctx, options, str, str, storage, canonized);
-    }
     if (options & LY_TYPE_OPTS_DYNAMIC) {
-        free((char*)value);
+        storage->canonical = lydict_insert_zc(ctx, (char*)value);
+    } else {
+        storage->canonical = lydict_insert(ctx, value, value_len);
     }
+    storage->boolean = i;
+    storage->realtype = type;
 
     return LY_SUCCESS;
 }
 
-/* @brief Duplication callback of the boolean values.
- *
- * Implementation of the ly_type_dup_clb.
- */
-static LY_ERR
-ly_type_dup_boolean(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
-{
-    dup->int64 = original->int64;
-    return ly_type_dup_original(ctx, original, dup);
-}
-
 /**
  * @brief Validate and store value of the YANG built-in empty type.
  *
  * Implementation of the ly_type_store_clb.
  */
 static LY_ERR
-ly_type_store_empty(const struct ly_ctx *ctx, struct lysc_type *UNUSED(type), const char *value, size_t value_len, int options,
+ly_type_store_empty(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
                     LY_PREFIX_FORMAT UNUSED(format), void *UNUSED(prefix_data),
                     const void *UNUSED(context_node), const struct lyd_node *UNUSED(tree),
-                    struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
+                    struct lyd_value *storage, struct ly_err_item **err)
 {
     if (options & LY_TYPE_OPTS_SECOND_CALL) {
         return LY_SUCCESS;
@@ -1321,13 +1151,9 @@
         }
     }
 
-    if (options & (LY_TYPE_OPTS_CANONIZE | LY_TYPE_OPTS_STORE)) {
-        /* NOTE: despite the pointer is used in storage twice (original and canonical_cache), it is stored in dictionary
-         * just once. This works even without storage - the string is returned as canonized. In case both options are used,
-         * ly_type_store_strval() increases reference count in dictionary for canonized. */
-        const char *str = lydict_insert(ctx, "", 0);
-        ly_type_store_strval(ctx, options, str, str, storage, canonized);
-    }
+    storage->canonical = lydict_insert(ctx, "", 0);
+    storage->ptr = NULL;
+    storage->realtype = type;
 
     return LY_SUCCESS;
 }
@@ -1360,6 +1186,9 @@
     return LY_ENOTFOUND;
 }
 
+static const char *ly_type_print_identityref(const struct lyd_value *value, LY_PREFIX_FORMAT format, void *prefix_data,
+                                             int *dynamic);
+
 /**
  * @brief Validate, canonize and store value of the YANG built-in identiytref type.
  *
@@ -1368,17 +1197,16 @@
 static LY_ERR
 ly_type_store_identityref(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
                           LY_PREFIX_FORMAT format, void *prefix_data, const void *UNUSED(context_node),
-                          const struct lyd_node *UNUSED(tree),struct lyd_value *storage, const char **canonized,
-                          struct ly_err_item **err)
+                          const struct lyd_node *UNUSED(tree),struct lyd_value *storage, struct ly_err_item **err)
 {
     struct lysc_type_identityref *type_ident = (struct lysc_type_identityref *)type;
     const char *id_name, *prefix = value;
     size_t id_len, prefix_len;
-    char *errmsg = NULL;
+    char *errmsg = NULL, *str;
     const struct lys_module *mod;
     LY_ARRAY_COUNT_TYPE u;
     struct lysc_ident *ident = NULL, *identities;
-    int erc = 0;
+    int erc = 0, dyn;
 
     if (options & LY_TYPE_OPTS_SECOND_CALL) {
         return LY_SUCCESS;
@@ -1437,25 +1265,22 @@
     }
     if (u == LY_ARRAY_COUNT(type_ident->bases)) {
         /* no match */
-        erc = asprintf(&errmsg, "Invalid identityref \"%.*s\" value - identity not accepted by the type specification.", (int)value_len, value);
+        erc = asprintf(&errmsg, "Invalid identityref \"%.*s\" value - identity not accepted by the type specification.",
+                       (int)value_len, value);
         goto error;
     }
 
-    if (options & LY_TYPE_OPTS_CANONIZE) {
-        /* identityref does not have a canonical form - to make it clear, the canonized form is represented as NULL */
-        *canonized = NULL;
-    }
+    storage->ident = ident;
 
-    if (options & LY_TYPE_OPTS_STORE) {
-        storage->ident = ident;
-        storage->canonical_cache = NULL;
-        storage->original = lydict_insert(ctx, value, value_len);
-    }
+    /* get JSON form since there is no canonical */
+    str = (char *)ly_type_print_identityref(storage, LY_PREF_JSON, NULL, &dyn);
+    assert(str && dyn);
+    storage->canonical = lydict_insert_zc(ctx, str);
+    storage->realtype = type;
 
     if (options & LY_TYPE_OPTS_DYNAMIC) {
-        free((char*)value);
+        free((char *)value);
     }
-
     return LY_SUCCESS;
 
 error:
@@ -1500,16 +1325,8 @@
     }
 }
 
-/* @brief Duplication callback of the identityref values.
- *
- * Implementation of the ly_type_dup_clb.
- */
-static LY_ERR
-ly_type_dup_identityref(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *original, struct lyd_value *dup)
-{
-    dup->ident = original->ident;
-    return LY_SUCCESS;
-}
+static const char *ly_type_print_instanceid(const struct lyd_value *value, LY_PREFIX_FORMAT format, void *prefix_data,
+                                            int *dynamic);
 
 /**
  * @brief Validate and store value of the YANG built-in instance-identifier type.
@@ -1519,17 +1336,16 @@
 static LY_ERR
 ly_type_store_instanceid(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
                          LY_PREFIX_FORMAT format, void *prefix_data, const void *context_node, const struct lyd_node *tree,
-                         struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
+                         struct lyd_value *storage, struct ly_err_item **err)
 {
     LY_ERR ret = LY_EVALID;
     struct lysc_type_instanceid *type_inst = (struct lysc_type_instanceid *)type;
-    char *errmsg = NULL;
+    char *errmsg = NULL, *str;
     struct ly_path *path = NULL;
     struct ly_set predicates = {0};
     struct lyxp_expr *exp = NULL;
     const struct lysc_node *ctx_scnode;
-    int erc = 0;
-    int prefix_opt = 0;
+    int erc = 0, prefix_opt = 0, dyn;
 
     /* init */
     *err = NULL;
@@ -1537,10 +1353,9 @@
                  (struct lysc_node *)context_node : ((struct lyd_node *)context_node)->schema;
 
     if ((options & LY_TYPE_OPTS_SCHEMA) && (options & LY_TYPE_OPTS_INCOMPLETE_DATA)) {
-        /* we have incomplete schema tree, so we are actually just storing the original value for future validation */
-        if (options & LY_TYPE_OPTS_STORE) {
-            storage->original = lydict_insert(ctx, value_len ? value : "", value_len);
-        }
+        /* we have incomplete schema tree */
+        /* HACK temporary storing of the original value */
+        storage->canonical = lydict_insert(ctx, value_len ? value : "", value_len);
         goto cleanup;
     }
 
@@ -1554,7 +1369,7 @@
         break;
     }
 
-    if (!(options & LY_TYPE_OPTS_SCHEMA) && (options & LY_TYPE_OPTS_SECOND_CALL) && (options & LY_TYPE_OPTS_STORE)) {
+    if (!(options & LY_TYPE_OPTS_SCHEMA) && (options & LY_TYPE_OPTS_SECOND_CALL)) {
         /* the second run in data tree, the first one ended with LY_EINCOMPLETE, but we have prepared the target structure */
         if (ly_path_eval(storage->target, tree, NULL)) {
             /* in error message we print the JSON format of the instance-identifier - in case of XML, it is not possible
@@ -1563,7 +1378,7 @@
             const char *id = storage->realtype->plugin->print(storage, LY_PREF_JSON, NULL, &dynamic);
             erc = asprintf(&errmsg, "Invalid instance-identifier \"%s\" value - required instance not found.", id);
             if (dynamic) {
-                free((char*)id);
+                free((char *)id);
             }
             /* we have to clean up the storage */
             type->plugin->free(ctx, storage);
@@ -1598,29 +1413,27 @@
         }
     }
 
+    /* HACK remove previously stored original value */
+    lydict_remove(ctx, storage->canonical);
+
     /* store resolved schema path */
-    if (options & LY_TYPE_OPTS_STORE) {
-        storage->target = path;
-        path = NULL;
-        if (!storage->original) {
-            /* it may be already present from the first call, in case this is the second */
-            storage->original = lydict_insert(ctx, value_len ? value : "", value_len);
-        }
-    }
+    storage->target = path;
+    path = NULL;
+
+    /* store JSON string value */
+    str = (char *)ly_type_print_instanceid(storage, LY_PREF_JSON, NULL, &dyn);
+    assert(str && dyn);
+    storage->canonical = lydict_insert_zc(ctx, str);
+
+    storage->realtype = type;
 
 cleanup:
     ly_set_erase(&predicates, NULL);
     lyxp_expr_free(ctx, exp);
     ly_path_free(ctx, path);
 
-    if (options & LY_TYPE_OPTS_CANONIZE) {
-        /* instance-identifier does not have a canonical form (lexical representation in in XML and JSON are
-         * even different) - to make it clear, the canonized form is represented as NULL */
-        *canonized = NULL;
-    }
-
     if (options & LY_TYPE_OPTS_DYNAMIC) {
-        free((char*)value);
+        free((char *)value);
     }
 
     if ((options & LY_TYPE_OPTS_INCOMPLETE_DATA) && ((options & LY_TYPE_OPTS_SCHEMA) || type_inst->require_instance)) {
@@ -1713,10 +1526,9 @@
     LY_ARRAY_COUNT_TYPE u, v;
     char *result = NULL;
 
-    if (!value->target && value->canonical_cache) {
-        /* value was not fully processed, but we have the original value so return it's copy */
-        *dynamic = 1;
-        return strdup(value->canonical_cache);
+    if (!value->target) {
+        /* value was not fully processed */
+        return NULL;
     }
 
     if ((format == LY_PREF_XML) || (format == LY_PREF_SCHEMA)) {
@@ -1837,6 +1649,8 @@
 static LY_ERR
 ly_type_dup_instanceid(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
 {
+    dup->canonical = lydict_insert(ctx, original->canonical, strlen(original->canonical));
+    dup->realtype = original->realtype;
     return ly_path_dup(ctx, original->target, &dup->target);
 }
 
@@ -1850,7 +1664,7 @@
 {
     ly_path_free(ctx, value->target);
     value->target = NULL;
-    ly_type_free_original(ctx, value);
+    ly_type_free_simple(ctx, value);
 }
 
 LY_ERR
@@ -1922,13 +1736,11 @@
 static LY_ERR
 ly_type_store_leafref(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
                       LY_PREFIX_FORMAT format, void *prefix_data, const void *context_node, const struct lyd_node *tree,
-                      struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
+                      struct lyd_value *storage, struct ly_err_item **err)
 {
     LY_ERR ret = LY_SUCCESS;
     char *errmsg = NULL;
     struct lysc_type_leafref *type_lr = (struct lysc_type_leafref *)type;
-    int storage_dummy = 0;
-    const char *orig = NULL;
     struct ly_path *p = NULL;
     struct ly_set *set = NULL;
 
@@ -1937,11 +1749,6 @@
             /* leafref's path was not yet resolved - in schema trees, path can be resolved when
              * the complete schema tree is present, in such a case we need to wait with validating
              * default values */
-
-            /* keep the original value for the second call */
-            if (options & LY_TYPE_OPTS_STORE) {
-                storage->original = lydict_insert(ctx, value_len ? value : "", value_len);
-            }
             return LY_EINCOMPLETE;
         } else {
             LOGINT(ctx);
@@ -1949,28 +1756,7 @@
         }
     }
 
-    if (!(options & (LY_TYPE_OPTS_STORE | LY_TYPE_OPTS_INCOMPLETE_DATA)) && type_lr->require_instance) {
-        /* if there is no storage, but we will check the instance presence in data tree(s),
-         * we need some (dummy) storage for data comparison */
-        storage = calloc(1, sizeof *storage);
-        storage_dummy = 1;
-    }
-    /* rewrite leafref plugin stored in the storage by default */
-    storage->realtype = type_lr->realtype;
-
     if ((options & LY_TYPE_OPTS_SCHEMA) && (options & LY_TYPE_OPTS_SECOND_CALL)) {
-        /* second call after missing resolved path (target's type) for a default value */
-        /* correct refcounts - leafref's realtype was set to itself in the first incomplete call,
-         * since we are now changing realtype to point to the target's realtype, we have to decrese
-         * leafref's refcount and increase realtype's refcount. */
-        type->refcount--;
-        storage->realtype->refcount++;
-
-        /* remove temporarily stored original value and let the following store callback
-         * to replace it via a target's type functions */
-        orig = storage->original;
-        storage->original = NULL;
-
         /* hide the LY_TYPE_OPTS_SECOND_CALL option from the target's store callback, the option is connected
          * only with the leafref's path, so it is not supposed to be used here. If the previous LY_EINCOMPLETE would
          * be caused by the target's type, the target type's callback would be used directly, not via leafref's callback */
@@ -1979,11 +1765,14 @@
 
     /* 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, format, prefix_data,
-                                           context_node, tree, storage, canonized, err);
+                                           context_node, tree, storage, err);
     if (ret != LY_SUCCESS && ret != LY_EINCOMPLETE) {
         goto cleanup;
     }
 
+    /* rewrite leafref plugin stored in the storage by default */
+    storage->realtype = type_lr->realtype;
+
     if (!(options & LY_TYPE_OPTS_SCHEMA) && type_lr->require_instance) {
         if (options & LY_TYPE_OPTS_INCOMPLETE_DATA) {
             ret = LY_EINCOMPLETE;
@@ -2000,11 +1789,6 @@
     }
 
 cleanup:
-    if (storage_dummy) {
-        storage->realtype->plugin->free(ctx, storage);
-        free(storage);
-    }
-    lydict_remove(ctx, orig);
     ly_path_free(ctx, p);
     ly_set_free(set, NULL);
     return ret;
@@ -2053,9 +1837,6 @@
     if (value->realtype->plugin != &ly_builtin_type_plugins[LY_TYPE_LEAFREF]) {
         /* leafref's realtype is again leafref only in case of incomplete store */
         value->realtype->plugin->free(ctx, value);
-    } else {
-        /* freeing incomplete type, there is original value to free */
-        ly_type_free_original(ctx, value);
     }
 }
 
@@ -2284,7 +2065,7 @@
 static LY_ERR
 ly_type_store_union(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
                     LY_PREFIX_FORMAT format, void *prefix_data, const void *context_node, const struct lyd_node *tree,
-                    struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
+                    struct lyd_value *storage, struct ly_err_item **err)
 {
     LY_ERR ret = LY_SUCCESS;
     LY_ARRAY_COUNT_TYPE u;
@@ -2293,104 +2074,97 @@
     char *errmsg = NULL;
     int prev_lo;
 
-    if ((options & LY_TYPE_OPTS_SECOND_CALL) && (options & LY_TYPE_OPTS_STORE)) {
+    if (options & LY_TYPE_OPTS_SECOND_CALL) {
         subvalue = storage->subvalue;
 
         /* 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),
+        ret = subvalue->value->realtype->plugin->store(ctx, subvalue->value->realtype, subvalue->original,
+                                                       strlen(subvalue->original), options & ~LY_TYPE_OPTS_DYNAMIC,
                                                        subvalue->format, subvalue->prefix_data, context_node, tree,
-                                                       subvalue->value, canonized, 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;
+                                                       subvalue->value, err);
+        if (ret == LY_SUCCESS) {
+            /* storing successful */
+            return LY_SUCCESS;
         }
+
+        /* 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;
     } else {
         /* prepare subvalue storage */
         subvalue = calloc(1, sizeof *subvalue);
         subvalue->value = calloc(1, sizeof *subvalue->value);
 
+        /* remember the original value */
+        subvalue->original = lydict_insert(ctx, value_len ? value : "", value_len);
+
         /* store format-specific data for later prefix resolution */
         subvalue->format = format;
         subvalue->prefix_data = ly_type_union_store_prefix_data(ctx, value, value_len, format, prefix_data);
 
         /* remember the hint options */
         subvalue->parser_hint = options & LY_TYPE_PARSER_HINTS_MASK;
-
-search_subtype:
-        /* use the first usable sybtype to store the value */
-        LY_ARRAY_FOR(type_u->types, u) {
-            subvalue->value->realtype = type_u->types[u];
-
-            if (type_check_parser_hint(format, subvalue->parser_hint, subvalue->value->realtype->basetype)) {
-                /* not a suitable type */
-                continue;
-            }
-
-            /* turn logging off */
-            prev_lo = ly_log_options(0);
-            ret = type_u->types[u]->plugin->store(ctx, type_u->types[u], value, value_len, options & ~LY_TYPE_OPTS_DYNAMIC,
-                                                  subvalue->format, subvalue->prefix_data, context_node, tree, subvalue->value,
-                                                  canonized, err);
-            /* restore logging */
-            ly_log_options(prev_lo);
-            if (ret == LY_SUCCESS || ret == LY_EINCOMPLETE) {
-                /* success (or not yet complete) */
-                break;
-            }
-            ly_err_free(*err);
-            *err = NULL;
-        }
-
-        if (u == LY_ARRAY_COUNT(type_u->types)) {
-            if (asprintf(&errmsg, "Invalid union value \"%.*s\" - no matching subtype found.", (int)value_len, value) == -1) {
-                *err = ly_err_new(LY_LLERR, LY_EMEM, 0, "Memory allocation failed.", NULL, NULL);
-                ret = LY_EMEM;
-            } else {
-                *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_DATA, errmsg, NULL, NULL);
-                ret = LY_EVALID;
-            }
-
-            /* free any stored information */
-            subvalue->value->realtype->plugin->free(ctx, subvalue->value);
-            free(subvalue->value);
-            ly_type_union_free_prefix_data(subvalue->format, subvalue->prefix_data);
-            free(subvalue);
-            if ((options & LY_TYPE_OPTS_SECOND_CALL) && (options & LY_TYPE_OPTS_STORE)) {
-                storage->subvalue = NULL;
-            }
-            return ret;
-        }
-
-        if ((options & LY_TYPE_OPTS_STORE) && !storage->original) {
-            storage->original = lydict_insert(ctx, value_len ? value : "", value_len);
-        }
     }
+
+    /* use the first usable sybtype to store the value */
+    LY_ARRAY_FOR(type_u->types, u) {
+        if (type_check_parser_hint(format, subvalue->parser_hint, type_u->types[u]->basetype)) {
+            /* not a suitable type */
+            continue;
+        }
+
+        /* turn logging off */
+        prev_lo = ly_log_options(0);
+        ret = type_u->types[u]->plugin->store(ctx, type_u->types[u], subvalue->original, strlen(subvalue->original),
+                                              options & ~LY_TYPE_OPTS_DYNAMIC, subvalue->format, subvalue->prefix_data,
+                                              context_node, tree, subvalue->value, err);
+        /* restore logging */
+        ly_log_options(prev_lo);
+        if (ret == LY_SUCCESS || ret == LY_EINCOMPLETE) {
+            /* success (or not yet complete) */
+            break;
+        }
+        ly_err_free(*err);
+        *err = NULL;
+    }
+
+    if (u == LY_ARRAY_COUNT(type_u->types)) {
+        if (asprintf(&errmsg, "Invalid union value \"%.*s\" - no matching subtype found.", (int)value_len, value) == -1) {
+            *err = ly_err_new(LY_LLERR, LY_EMEM, 0, "Memory allocation failed.", NULL, NULL);
+            ret = LY_EMEM;
+        } else {
+            *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_DATA, errmsg, NULL, NULL);
+            ret = LY_EVALID;
+        }
+
+        /* free any stored information */
+        free(subvalue->value);
+        lydict_remove(ctx, subvalue->original);
+        ly_type_union_free_prefix_data(subvalue->format, subvalue->prefix_data);
+        free(subvalue);
+        if (options & LY_TYPE_OPTS_SECOND_CALL) {
+            storage->subvalue = NULL;
+        }
+        return ret;
+    }
+
     /* success */
 
+    storage->canonical = lydict_insert(ctx, subvalue->value->canonical, strlen(subvalue->value->canonical));
+    storage->subvalue = subvalue;
+    storage->realtype = type;
+
     if (options & LY_TYPE_OPTS_DYNAMIC) {
         free((char *)value);
     }
-
-    if (options & LY_TYPE_OPTS_STORE) {
-        storage->subvalue = subvalue;
-    } else {
-        subvalue->value->realtype->plugin->free(ctx, subvalue->value);
-        free(subvalue->value);
-        ly_type_union_free_prefix_data(subvalue->format, subvalue->prefix_data);
-        free(subvalue);
-    }
-
     return ret;
 }
 
@@ -2419,24 +2193,29 @@
     return value->subvalue->value->realtype->plugin->print(value->subvalue->value, format, prefix_data, dynamic);
 }
 
-/* @brief Duplication callback of the union values.
+/**
+ * @brief Duplication callback of the union values.
  *
  * Implementation of the ly_type_dup_clb.
  */
 static LY_ERR
 ly_type_dup_union(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
 {
+    dup->canonical = lydict_insert(ctx, original->canonical, strlen(original->canonical));
+
     dup->subvalue = calloc(1, sizeof *dup->subvalue);
     LY_CHECK_ERR_RET(!dup->subvalue, LOGMEM(ctx), LY_EMEM);
+    dup->subvalue->value = calloc(1, sizeof *dup->subvalue->value);
+    LY_CHECK_ERR_RET(!dup->subvalue->value, LOGMEM(ctx), LY_EMEM);
+    original->subvalue->value->realtype->plugin->duplicate(ctx, original->subvalue->value, dup->subvalue->value);
+
+    dup->subvalue->original = lydict_insert(ctx, original->subvalue->original, strlen(original->subvalue->original));
     dup->subvalue->format = original->subvalue->format;
     dup->subvalue->prefix_data = ly_type_union_dup_prefix_data(ctx, original->subvalue->format,
                                                                original->subvalue->prefix_data);
-    dup->subvalue->value = calloc(1, sizeof *dup->subvalue->value);
-    LY_CHECK_ERR_RET(!dup->subvalue->value, LOGMEM(ctx), LY_EMEM);
-    dup->subvalue->value->realtype = original->subvalue->value->realtype;
-    dup->subvalue->value->realtype->plugin->duplicate(ctx, original->subvalue->value, dup->subvalue->value);
 
-    return ly_type_dup_original(ctx, original, dup);
+    dup->realtype = original->realtype;
+    return LY_SUCCESS;
 }
 
 /**
@@ -2447,16 +2226,17 @@
 static void
 ly_type_free_union(const struct ly_ctx *ctx, struct lyd_value *value)
 {
+    lydict_remove(ctx, value->canonical);
     if (value->subvalue) {
         if (value->subvalue->value) {
             value->subvalue->value->realtype->plugin->free(ctx, value->subvalue->value);
             free(value->subvalue->value);
             ly_type_union_free_prefix_data(value->subvalue->format, value->subvalue->prefix_data);
         }
+        lydict_remove(ctx, value->subvalue->original);
         free(value->subvalue);
         value->subvalue = NULL;
     }
-    ly_type_free_canonical(ctx, value);
 }
 
 /**
@@ -2464,41 +2244,41 @@
  */
 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,
-        .print = ly_type_print_canonical, .duplicate = ly_type_dup_canonical, .free = ly_type_free_canonical,
+    {.type = LY_TYPE_BINARY, .store = ly_type_store_binary, .compare = ly_type_compare_simple,
+        .print = ly_type_print_simple, .duplicate = ly_type_dup_simple, .free = ly_type_free_simple,
         .id = "libyang 2 - binary, version 1"},
-    {.type = LY_TYPE_UINT8, .store = ly_type_store_uint, .compare = ly_type_compare_canonical,
-        .print = ly_type_print_canonical, .duplicate = ly_type_dup_uint, .free = ly_type_free_canonical,
+    {.type = LY_TYPE_UINT8, .store = ly_type_store_uint, .compare = ly_type_compare_simple,
+        .print = ly_type_print_simple, .duplicate = ly_type_dup_simple, .free = ly_type_free_simple,
         .id = "libyang 2 - unsigned integer, version 1"},
-    {.type = LY_TYPE_UINT16, .store = ly_type_store_uint, .compare = ly_type_compare_canonical,
-        .print = ly_type_print_canonical, .duplicate = ly_type_dup_uint, .free = ly_type_free_canonical,
+    {.type = LY_TYPE_UINT16, .store = ly_type_store_uint, .compare = ly_type_compare_simple,
+        .print = ly_type_print_simple, .duplicate = ly_type_dup_simple, .free = ly_type_free_simple,
         .id = "libyang 2 - unsigned integer, version 1"},
-    {.type = LY_TYPE_UINT32, .store = ly_type_store_uint, .compare = ly_type_compare_canonical,
-        .print = ly_type_print_canonical, .duplicate = ly_type_dup_uint, .free = ly_type_free_canonical,
+    {.type = LY_TYPE_UINT32, .store = ly_type_store_uint, .compare = ly_type_compare_simple,
+        .print = ly_type_print_simple, .duplicate = ly_type_dup_simple, .free = ly_type_free_simple,
         .id = "libyang 2 - unsigned integer, version 1"},
-    {.type = LY_TYPE_UINT64, .store = ly_type_store_uint, .compare = ly_type_compare_canonical,
-        .print = ly_type_print_canonical, .duplicate = ly_type_dup_uint, .free = ly_type_free_canonical,
+    {.type = LY_TYPE_UINT64, .store = ly_type_store_uint, .compare = ly_type_compare_simple,
+        .print = ly_type_print_simple, .duplicate = ly_type_dup_simple, .free = ly_type_free_simple,
         .id = "libyang 2 - unsigned integer, version 1"},
-    {.type = LY_TYPE_STRING, .store = ly_type_store_string, .compare = ly_type_compare_canonical,
-        .print = ly_type_print_canonical, .duplicate = ly_type_dup_original, .free = ly_type_free_original,
+    {.type = LY_TYPE_STRING, .store = ly_type_store_string, .compare = ly_type_compare_simple,
+        .print = ly_type_print_simple, .duplicate = ly_type_dup_simple, .free = ly_type_free_simple,
         .id = "libyang 2 - string, version 1"},
-    {.type = LY_TYPE_BITS, .store = ly_type_store_bits, .compare = ly_type_compare_canonical,
-        .print = ly_type_print_canonical, .duplicate = ly_type_dup_bits, .free = ly_type_free_bits,
+    {.type = LY_TYPE_BITS, .store = ly_type_store_bits, .compare = ly_type_compare_simple,
+        .print = ly_type_print_simple, .duplicate = ly_type_dup_bits, .free = ly_type_free_bits,
         .id = "libyang 2 - bits, version 1"},
-    {.type = LY_TYPE_BOOL, .store = ly_type_store_boolean, .compare = ly_type_compare_canonical,
-        .print = ly_type_print_canonical, .duplicate = ly_type_dup_boolean, .free = ly_type_free_original,
+    {.type = LY_TYPE_BOOL, .store = ly_type_store_boolean, .compare = ly_type_compare_simple,
+        .print = ly_type_print_simple, .duplicate = ly_type_dup_simple, .free = ly_type_free_simple,
         .id = "libyang 2 - boolean, version 1"},
-    {.type = LY_TYPE_DEC64, .store = ly_type_store_decimal64, .compare = ly_type_compare_canonical,
-        .print = ly_type_print_canonical, .duplicate = ly_type_dup_decimal64, .free = ly_type_free_canonical,
+    {.type = LY_TYPE_DEC64, .store = ly_type_store_decimal64, .compare = ly_type_compare_simple,
+        .print = ly_type_print_simple, .duplicate = ly_type_dup_simple, .free = ly_type_free_simple,
         .id = "libyang 2 - decimal64, version 1"},
     {.type = LY_TYPE_EMPTY, .store = ly_type_store_empty, .compare = ly_type_compare_empty,
-        .print = ly_type_print_canonical, .duplicate = ly_type_dup_original, .free = ly_type_free_original,
+        .print = ly_type_print_simple, .duplicate = ly_type_dup_simple, .free = ly_type_free_simple,
         .id = "libyang 2 - empty, version 1"},
-    {.type = LY_TYPE_ENUM, .store = ly_type_store_enum, .compare = ly_type_compare_canonical,
-        .print = ly_type_print_canonical, .duplicate = ly_type_dup_enum, .free = ly_type_free_original,
+    {.type = LY_TYPE_ENUM, .store = ly_type_store_enum, .compare = ly_type_compare_simple,
+        .print = ly_type_print_simple, .duplicate = ly_type_dup_simple, .free = ly_type_free_simple,
         .id = "libyang 2 - enumeration, version 1"},
     {.type = LY_TYPE_IDENT, .store = ly_type_store_identityref, .compare = ly_type_compare_identityref,
-        .print = ly_type_print_identityref, .duplicate = ly_type_dup_identityref, .free = ly_type_free_canonical,
+        .print = ly_type_print_identityref, .duplicate = ly_type_dup_simple, .free = ly_type_free_simple,
         .id = "libyang 2 - identityref, version 1"},
     {.type = LY_TYPE_INST, .store = ly_type_store_instanceid, .compare = ly_type_compare_instanceid,
         .print = ly_type_print_instanceid, .duplicate = ly_type_dup_instanceid, .free = ly_type_free_instanceid,
@@ -2509,16 +2289,16 @@
     {.type = LY_TYPE_UNION, .store = ly_type_store_union, .compare = ly_type_compare_union,
         .print = ly_type_print_union, .duplicate = ly_type_dup_union, .free = ly_type_free_union,
         .id = "libyang 2 - union,version 1"},
-    {.type = LY_TYPE_INT8, .store = ly_type_store_int, .compare = ly_type_compare_canonical,
-        .print = ly_type_print_canonical, .duplicate = ly_type_dup_int, .free = ly_type_free_canonical,
+    {.type = LY_TYPE_INT8, .store = ly_type_store_int, .compare = ly_type_compare_simple,
+        .print = ly_type_print_simple, .duplicate = ly_type_dup_simple, .free = ly_type_free_simple,
         .id = "libyang 2 - integer, version 1"},
-    {.type = LY_TYPE_INT16, .store = ly_type_store_int, .compare = ly_type_compare_canonical,
-        .print = ly_type_print_canonical, .duplicate = ly_type_dup_int, .free = ly_type_free_canonical,
+    {.type = LY_TYPE_INT16, .store = ly_type_store_int, .compare = ly_type_compare_simple,
+        .print = ly_type_print_simple, .duplicate = ly_type_dup_simple, .free = ly_type_free_simple,
         .id = "libyang 2 - integer, version 1"},
-    {.type = LY_TYPE_INT32, .store = ly_type_store_int, .compare = ly_type_compare_canonical,
-        .print = ly_type_print_canonical, .duplicate = ly_type_dup_int, .free = ly_type_free_canonical,
+    {.type = LY_TYPE_INT32, .store = ly_type_store_int, .compare = ly_type_compare_simple,
+        .print = ly_type_print_simple, .duplicate = ly_type_dup_simple, .free = ly_type_free_simple,
         .id = "libyang 2 - integer, version 1"},
-    {.type = LY_TYPE_INT64, .store = ly_type_store_int, .compare = ly_type_compare_canonical,
-        .print = ly_type_print_canonical, .duplicate = ly_type_dup_int, .free = ly_type_free_canonical,
+    {.type = LY_TYPE_INT64, .store = ly_type_store_int, .compare = ly_type_compare_simple,
+        .print = ly_type_print_simple, .duplicate = ly_type_dup_simple, .free = ly_type_free_simple,
         .id = "libyang 2 - integer, version 1"},
 };
diff --git a/src/plugins_types.h b/src/plugins_types.h
index a0a187b..fdd85c8 100644
--- a/src/plugins_types.h
+++ b/src/plugins_types.h
@@ -136,26 +136,23 @@
 /**
  * @defgroup plugintypeopts Options for type plugin callbacks. The same set of the options is passed to all the type's callbacks used together.
  *
- * Options applicable to ly_type_validate_clb() and ly_type_store_clb.
+ * Options applicable to ly_type_store_clb().
  * @{
  */
-#define LY_TYPE_OPTS_CANONIZE     0x01 /**< Canonize the given value and store it (insert into the context's dictionary)
-                                            as the value's canonized string */
-#define LY_TYPE_OPTS_DYNAMIC      0x02 /**< Flag for the dynamically allocated string value, in this case the value
+#define LY_TYPE_OPTS_DYNAMIC      0x01 /**< Flag for the dynamically allocated string value, in this case the value
                                             is supposed to be freed or directly inserted into the context's dictionary
                                             (e.g. in case of canonization).
                                             In any case, the caller of the callback does not free the provided string value after calling
                                             the type's callbacks with this option */
-#define LY_TYPE_OPTS_STORE        0x04 /**< Flag announcing calling of ly_type_store_clb() */
-#define LY_TYPE_OPTS_SCHEMA       0x08 /**< Flag for the value used in schema instead of the data tree. With this flag also the meaning of
+#define LY_TYPE_OPTS_SCHEMA       0x02 /**< Flag for the value used in schema instead of the data tree. With this flag also the meaning of
                                             LY_TYPE_OPTS_INCOMPLETE_DATA changes and means that the schema tree is not complete (data tree
                                             is not taken into account at all). */
-#define LY_TYPE_OPTS_INCOMPLETE_DATA 0x10 /**< Flag for the case the data trees (schema trees in case it is used in combination with
+#define LY_TYPE_OPTS_INCOMPLETE_DATA 0x04 /**< Flag for the case the data trees (schema trees in case it is used in combination with
                                             LY_TYPE_OPTS_SCHEMA) are not yet complete. In this case the plugin should do what it
                                             can (e.g. store the canonical/auxiliary value if it is requested) and in the case of need to use
                                             data trees (checking require-instance), it returns LY_EINCOMPLETE.
                                             Caller is supposed to call such validation callback again later with complete data trees. */
-#define LY_TYPE_OPTS_SECOND_CALL  0x20 /**< Flag for the second call of the callback when the first call returns LY_EINCOMPLETE,
+#define LY_TYPE_OPTS_SECOND_CALL  0x08 /**< Flag for the second call of the callback when the first call returns LY_EINCOMPLETE,
                                             other options should be the same as for the first call. **!!** Note that this second call
                                             can occur even if the first call succeeded, in which case the plugin should immediately
                                             return LY_SUCCESS. */
@@ -195,11 +192,7 @@
  *            This argument is a lys_node (in case LY_TYPE_OPTS_INCOMPLETE_DATA or LY_TYPE_OPTS_SCHEMA set in @p options)
  *            or lyd_node structure.
  * @param[in] tree External data tree (e.g. when validating RPC/Notification) where the required data instance can be placed.
- * @param[in,out] storage If LY_TYPE_OPTS_STORE option set, the parsed data are stored into this structure in the type's specific way.
- *             If the @p canonized differs from the storage's canonized member, the canonized value is also stored here despite the
- *             LY_TYPE_OPTS_CANONIZE option.
- * @param[out] canonized If LY_TYPE_OPTS_CANONIZE option set, the canonized string stored in the @p ctx dictionary
- *             is returned via this parameter.
+ * @param[in] storage Storage for the value in the type's specific encoding. All the members should be filled by the plugin.
  * @param[out] err Optionally provided error information in case of failure. If not provided to the caller, a generic
  *             error message is prepared instead.
  *             The error structure can be created by ly_err_new().
@@ -209,8 +202,7 @@
  */
 typedef LY_ERR (*ly_type_store_clb)(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len,
                                     int options, LY_PREFIX_FORMAT format, void *prefix_data, const void *context_node,
-                                    const struct lyd_node *tree, struct lyd_value *storage, const char **canonized,
-                                    struct ly_err_item **err);
+                                    const struct lyd_node *tree, struct lyd_value *storage, struct ly_err_item **err);
 
 /**
  * @brief Callback for comparing 2 values of the same type.
diff --git a/src/printer_lyb.c b/src/printer_lyb.c
index 554d6b4..a99c8dc 100644
--- a/src/printer_lyb.c
+++ b/src/printer_lyb.c
@@ -672,20 +672,8 @@
 static LY_ERR
 lyb_print_term(struct lyd_node_term *term, struct ly_out *out, struct lylyb_ctx *lybctx)
 {
-    LY_ERR ret;
-    int dynamic;
-    const char *str;
-
-    /* get value */
-    str = lyd_value2str(term, &dynamic);
-
-    /* print it */
-    ret = lyb_write_string(str, 0, 0, out, lybctx);
-
-    if (dynamic) {
-        free((char *)str);
-    }
-    return ret;
+    /* print the value */
+    return lyb_write_string(LYD_CANONICAL(term), 0, 0, out, lybctx);
 }
 
 /**
@@ -699,12 +687,9 @@
 static LY_ERR
 lyb_print_metadata(struct ly_out *out, const struct lyd_node *node, struct lyd_lyb_ctx *lybctx)
 {
-    LY_ERR ret;
-    int dynamic;
     uint8_t count = 0;
     const struct lys_module *wd_mod = NULL;
     struct lyd_meta *iter;
-    const char *str;
 
     /* with-defaults */
     if (node->schema->nodetype & LYD_NODE_TERM) {
@@ -750,15 +735,8 @@
         /* annotation name with length */
         LY_CHECK_RET(lyb_write_string(iter->name, 0, 1, out, lybctx->lybctx));
 
-        /* get the value */
-        str = lyd_meta2str(iter, &dynamic);
-
         /* metadata value */
-        ret = lyb_write_string(str, 0, 0, out, lybctx->lybctx);
-        if (dynamic) {
-            free((char *)str);
-        }
-        LY_CHECK_RET(ret);
+        LY_CHECK_RET(lyb_write_string(iter->value.canonical, 0, 0, out, lybctx->lybctx));
 
         /* finish metadata subtree */
         LY_CHECK_RET(lyb_write_stop_subtree(out, lybctx->lybctx));
diff --git a/src/printer_yang.c b/src/printer_yang.c
index 20b01b5..fb806de 100755
--- a/src/printer_yang.c
+++ b/src/printer_yang.c
@@ -928,12 +928,12 @@
 }
 
 static void
-yprc_dflt_value(struct ypr_ctx *ctx, const struct lyd_value *value, const struct lys_module *value_mod, struct lysc_ext_instance *exts)
+yprc_dflt_value(struct ypr_ctx *ctx, const struct lyd_value *value, struct lysc_ext_instance *exts)
 {
     int dynamic;
     const char *str;
 
-    str = value->realtype->plugin->print(value, LY_PREF_SCHEMA, (void *)value_mod, &dynamic);
+    str = value->realtype->plugin->print(value, LY_PREF_JSON, NULL, &dynamic);
     ypr_substmt(ctx, LYEXT_SUBSTMT_DEFAULT, 0, str, exts);
     if (dynamic) {
         free((void*)str);
@@ -950,10 +950,6 @@
     LEVEL++;
 
     yprc_extension_instances(ctx, LYEXT_SUBSTMT_SELF, 0, type->exts, &flag, 0);
-    if (type->dflt) {
-        ypr_open(ctx->out, &flag);
-        yprc_dflt_value(ctx, type->dflt, type->dflt_mod, type->exts);
-    }
 
     switch (type->basetype) {
     case LY_TYPE_BINARY: {
@@ -1577,7 +1573,7 @@
     }
 
     if (leaf->dflt) {
-        yprc_dflt_value(ctx, leaf->dflt, leaf->dflt_mod, leaf->exts);
+        yprc_dflt_value(ctx, leaf->dflt, leaf->exts);
     }
 
     yprc_node_common2(ctx, node, NULL);
@@ -1642,7 +1638,7 @@
         yprc_must(ctx, &llist->musts[u], NULL);
     }
     LY_ARRAY_FOR(llist->dflts, u) {
-        yprc_dflt_value(ctx, llist->dflts[u], llist->dflts_mods[u], llist->exts);
+        yprc_dflt_value(ctx, llist->dflts[u], llist->exts);
     }
 
     ypr_config(ctx, node->flags, node->exts, NULL);
diff --git a/src/tree_data.c b/src/tree_data.c
index 7e21f87..d8ef789 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -62,18 +62,15 @@
     struct ly_err_item *err = NULL;
     struct ly_ctx *ctx;
     struct lysc_type *type;
-    int options = value_hint | LY_TYPE_OPTS_STORE | (second ? LY_TYPE_OPTS_SECOND_CALL : 0) |
+    int options = value_hint | (second ? LY_TYPE_OPTS_SECOND_CALL : 0) |
             (dynamic && *dynamic ? LY_TYPE_OPTS_DYNAMIC : 0) | (tree ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
     assert(node);
 
     ctx = node->schema->module->ctx;
 
     type = ((struct lysc_node_leaf*)node->schema)->type;
-    if (!second) {
-        node->value.realtype = type;
-    }
     ret = type->plugin->store(ctx, type, value, value_len, options, format, prefix_data,
-                              tree ? (void *)node : (void *)node->schema, tree, &node->value, NULL, &err);
+                              tree ? (void *)node : (void *)node->schema, tree, &node->value, &err);
     if (ret && (ret != LY_EINCOMPLETE)) {
         if (err) {
             /* node may not be connected yet so use the schema node */
@@ -102,15 +99,14 @@
     struct ly_err_item *err = NULL;
     struct ly_ctx *ctx;
     struct lysc_type *type;
-    int options = LY_TYPE_OPTS_STORE | LY_TYPE_OPTS_INCOMPLETE_DATA | (dynamic && *dynamic ? LY_TYPE_OPTS_DYNAMIC : 0);
+    int options = LY_TYPE_OPTS_INCOMPLETE_DATA | (dynamic && *dynamic ? LY_TYPE_OPTS_DYNAMIC : 0);
 
     assert(val && schema && (schema->nodetype & LYD_NODE_TERM));
 
     ctx = schema->module->ctx;
     type = ((struct lysc_node_leaf *)schema)->type;
-    val->realtype = type;
     ret = type->plugin->store(ctx, type, value, value_len, options, format, prefix_data, (void *)schema, NULL,
-                              val, NULL, &err);
+                              val, &err);
     if (ret == LY_EINCOMPLETE) {
         /* this is fine, we do not need it resolved */
         ret = LY_SUCCESS;
@@ -134,18 +130,14 @@
     LY_ERR ret = LY_SUCCESS;
     struct ly_err_item *err = NULL;
     struct lyext_metadata *ant;
-    int options = value_hint | LY_TYPE_OPTS_STORE | (second ? LY_TYPE_OPTS_SECOND_CALL : 0) |
+    int options = value_hint | (second ? LY_TYPE_OPTS_SECOND_CALL : 0) |
             (dynamic && *dynamic ? LY_TYPE_OPTS_DYNAMIC : 0) | (tree ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
 
     assert(ctx && meta && ((tree && meta->parent) || ctx_snode));
 
     ant = meta->annotation->data;
-
-    if (!second) {
-        meta->value.realtype = ant->type;
-    }
     ret = ant->type->plugin->store(ctx, ant->type, value, value_len, options, format, prefix_data,
-                                  tree ? (void *)meta->parent : (void *)ctx_snode, tree, &meta->value, NULL, &err);
+                                  tree ? (void *)meta->parent : (void *)ctx_snode, tree, &meta->value, &err);
     if (ret && (ret != LY_EINCOMPLETE)) {
         if (err) {
             ly_err_print(err);
@@ -167,6 +159,7 @@
 {
     LY_ERR rc = LY_SUCCESS;
     struct ly_err_item *err = NULL;
+    struct lyd_value storage;
     struct lysc_type *type;
 
     LY_CHECK_ARG_RET(ctx, node, value, LY_EINVAL);
@@ -179,7 +172,7 @@
     type = ((struct lysc_node_leaf*)node)->type;
     /* just validate, no storing of enything */
     rc = type->plugin->store(ctx ? ctx : node->module->ctx, type, value, value_len, LY_TYPE_OPTS_INCOMPLETE_DATA,
-                             format, prefix_data, node, NULL, NULL, NULL, &err);
+                             format, prefix_data, node, NULL, &storage, &err);
     if (rc == LY_EINCOMPLETE) {
         /* actually success since we do not provide the context tree and call validation with
          * LY_TYPE_OPTS_INCOMPLETE_DATA */
@@ -193,6 +186,9 @@
         ly_err_free(err);
     }
 
+    if (!rc) {
+        type->plugin->free(ctx ? ctx : node->module->ctx, &storage);
+    }
     return rc;
 }
 
@@ -210,13 +206,13 @@
     struct ly_err_item *err = NULL;
     struct lysc_type *type;
     struct lyd_value val = {0};
-    int options = (tree ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA) | (realtype ? LY_TYPE_OPTS_STORE : 0);
+    int options = (tree ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
 
     LY_CHECK_ARG_RET(ctx, node, value, LY_EINVAL);
 
     type = ((struct lysc_node_leaf*)node->schema)->type;
     rc = type->plugin->store(ctx ? ctx : node->schema->module->ctx, type, value, value_len, options, LY_PREF_JSON, NULL,
-                             tree ? (void*)node : (void*)node->schema, tree, &val, NULL, &err);
+                             tree ? (void*)node : (void*)node->schema, tree, &val, &err);
     if (rc == LY_EINCOMPLETE) {
         return rc;
     } else if (rc) {
@@ -246,14 +242,14 @@
     struct ly_ctx *ctx;
     struct lysc_type *type;
     struct lyd_value data = {0};
-    int options = LY_TYPE_OPTS_STORE | (tree ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
+    int options = (tree ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
 
     LY_CHECK_ARG_RET(node ? node->schema->module->ctx : NULL, node, value, LY_EINVAL);
 
     ctx = node->schema->module->ctx;
     type = ((struct lysc_node_leaf*)node->schema)->type;
     rc = type->plugin->store(ctx, type, value, value_len, options, LY_PREF_JSON, NULL, (struct lyd_node *)node, tree, &data,
-                             NULL, &err);
+                             &err);
     if (rc == LY_EINCOMPLETE) {
         ret = rc;
         /* continue with comparing, just remember what to return if storing is ok */
@@ -278,22 +274,6 @@
     return ret;
 }
 
-API const char *
-lyd_value2str(const struct lyd_node_term *node, int *dynamic)
-{
-    LY_CHECK_ARG_RET(node ? node->schema->module->ctx : NULL, node, dynamic, NULL);
-
-    return node->value.realtype->plugin->print(&node->value, LY_PREF_JSON, NULL, dynamic);
-}
-
-API const char *
-lyd_meta2str(const struct lyd_meta *meta, int *dynamic)
-{
-    LY_CHECK_ARG_RET(meta ? meta->parent->schema->module->ctx : NULL, meta, dynamic, NULL);
-
-    return meta->value.realtype->plugin->print(&meta->value, LY_PREF_JSON, NULL, dynamic);
-}
-
 static LYD_FORMAT
 lyd_parse_get_format(const struct ly_in *in, LYD_FORMAT format)
 {
@@ -588,7 +568,7 @@
     struct lysc_type *type;
 
     assert(schema->nodetype & LYD_NODE_TERM);
-    assert(val && val->realtype);
+    assert(val && val->canonical && val->realtype);
 
     term = calloc(1, sizeof *term);
     LY_CHECK_ERR_RET(!term, LOGMEM(schema->module->ctx), LY_EMEM);
@@ -604,7 +584,6 @@
         free(term);
         return ret;
     }
-    term->value.realtype = val->realtype;
     lyd_hash((struct lyd_node *)term);
 
     *node = (struct lyd_node *)term;
@@ -2582,8 +2561,7 @@
         struct lyd_node_term *orig = (struct lyd_node_term *)node;
 
         term->hash = orig->hash;
-        term->value.realtype = orig->value.realtype;
-        LY_CHECK_ERR_GOTO(term->value.realtype->plugin->duplicate(LYD_NODE_CTX(node), &orig->value, &term->value),
+        LY_CHECK_ERR_GOTO(orig->value.realtype->plugin->duplicate(LYD_NODE_CTX(node), &orig->value, &term->value),
                           LOGERR(LYD_NODE_CTX(node), LY_EINT, "Value duplication failed."); ret = LY_EINT, error);
     } else if (dup->schema->nodetype & LYD_NODE_INNER) {
         struct lyd_node_inner *orig = (struct lyd_node_inner *)node;
@@ -2753,8 +2731,7 @@
     LY_CHECK_ERR_RET(!mt, LOGMEM(LYD_NODE_CTX(node)), LY_EMEM);
     mt->parent = node;
     mt->annotation = meta->annotation;
-    mt->value.realtype = meta->value.realtype;
-    ret = mt->value.realtype->plugin->duplicate(LYD_NODE_CTX(node), &meta->value, &mt->value);
+    ret = meta->value.realtype->plugin->duplicate(LYD_NODE_CTX(node), &meta->value, &mt->value);
     LY_CHECK_ERR_RET(ret, LOGERR(LYD_NODE_CTX(node), LY_EINT, "Value duplication failed."), ret);
     mt->name = lydict_insert(LYD_NODE_CTX(node), meta->name, 0);
 
@@ -2928,32 +2905,20 @@
 lyd_path_list_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, int is_static)
 {
     const struct lyd_node *key;
-    int dynamic = 0;
     size_t len;
     const char *val;
     char quot;
-    LY_ERR rc;
 
     for (key = lyd_node_children(node, 0); key && (key->schema->flags & LYS_KEY); key = key->next) {
-        val = lyd_value2str((struct lyd_node_term *)key, &dynamic);
+        val = LYD_CANONICAL(key);
         len = 1 + strlen(key->schema->name) + 2 + strlen(val) + 2;
-        rc = lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static);
-        if (rc != LY_SUCCESS) {
-            if (dynamic) {
-                free((char *)val);
-            }
-            return rc;
-        }
+        LY_CHECK_RET(lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static));
 
         quot = '\'';
         if (strchr(val, '\'')) {
             quot = '"';
         }
         *bufused += sprintf(*buffer + *bufused, "[%s=%c%s%c]", key->schema->name, quot, val, quot);
-
-        if (dynamic) {
-            free((char *)val);
-        }
     }
 
     return LY_SUCCESS;
@@ -2972,18 +2937,13 @@
 static LY_ERR
 lyd_path_leaflist_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, int is_static)
 {
-    int dynamic = 0;
     size_t len;
     const char *val;
     char quot;
-    LY_ERR rc;
 
-    val = lyd_value2str((struct lyd_node_term *)node, &dynamic);
+    val = LYD_CANONICAL(node);
     len = 4 + strlen(val) + 2;
-    rc = lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static);
-    if (rc != LY_SUCCESS) {
-        goto cleanup;
-    }
+    LY_CHECK_RET(lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static));
 
     quot = '\'';
     if (strchr(val, '\'')) {
@@ -2991,11 +2951,7 @@
     }
     *bufused += sprintf(*buffer + *bufused, "[.=%c%s%c]", quot, val, quot);
 
-cleanup:
-    if (dynamic) {
-        free((char *)val);
-    }
-    return rc;
+    return LY_SUCCESS;
 }
 
 /**
diff --git a/src/tree_data.h b/src/tree_data.h
index 4f261ef..7c94d99 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -186,6 +186,7 @@
 struct lyd_value_subvalue {
     struct lyd_value *value;     /**< representation of the value according to the selected union's subtype
                                       (stored as lyd_value::realpath here, in subvalue structure */
+    const char *original;        /**< Original value in the dictionary. */
     LY_PREFIX_FORMAT format;     /**< Prefix format of the value. However, this information is also used to decide
                                       whether a value is valid for the specific format or not on later validations
                                       (instance-identifier in XML looks different than in JSON). */
@@ -197,8 +198,8 @@
  * @brief YANG data representation
  */
 struct lyd_value {
-    const char *original;           /**< Original string representation of the value. It is never NULL, but (canonical) string representation
-                                         of the value should be always obtained via the type's printer callback (lyd_value::realtype::plugin::print). */
+    const char *canonical;           /**< Canonical string representation of the value in the dictionary. It is never
+                                          NULL and in case of no canonical value, its JSON representation is used instead. */
     union {
         int8_t boolean;              /**< 0 as false, 1 as true */
         int64_t dec64;               /**< decimal64: value = dec64 / 10^fraction-digits  */
@@ -226,12 +227,17 @@
                                           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. */
-    void *canonical_cache;           /**< Generic cache for type plugins to store data necessary to print canonical value. It can be the canonical
-                                          value itself or anything else useful to print the canonical form of the value. Plugin is responsible for
-                                          freeing the cache in its free callback. */
 };
 
 /**
+ * @brief Macro for getting the string canonical value from a term node.
+ *
+ * @param[in] node Term node with the value.
+ * @return Canonical value.
+ */
+#define LYD_CANONICAL(node) ((struct lyd_node_term *)(node))->value.canonical
+
+/**
  * @brief Metadata structure.
  *
  * The structure provides information about metadata of a data element. Such attributes must map to
@@ -1244,24 +1250,6 @@
 const struct lyd_node_term *lyd_target(const struct ly_path *path, const struct lyd_node *tree);
 
 /**
- * @brief Get string value of a term data \p node.
- *
- * @param[in] node Data tree node with the value.
- * @param[out] dynamic Whether the string value was dynmically allocated.
- * @return String value of @p node, if @p dynamic, needs to be freed.
- */
-const char *lyd_value2str(const struct lyd_node_term *node, int *dynamic);
-
-/**
- * @brief Get string value of a metadata \p meta.
- *
- * @param[in] meta Metadata with the value.
- * @param[out] dynamic Whether the string value was dynmically allocated.
- * @return String value of @p meta, if @p dynamic, needs to be freed.
- */
-const char *lyd_meta2str(const struct lyd_meta *meta, int *dynamic);
-
-/**
  * @brief Types of the different data paths.
  */
 typedef enum {
diff --git a/src/tree_data_hash.c b/src/tree_data_hash.c
index d1756d9..cf2fb5f 100644
--- a/src/tree_data_hash.c
+++ b/src/tree_data_hash.c
@@ -65,32 +65,17 @@
         struct lyd_node_inner *list = (struct lyd_node_inner*)node;
         if (!(node->schema->flags & LYS_KEYLESS)) {
             /* list's hash is made of its keys */
-            struct lysc_node *key;
-            for (key = ((struct lysc_node_list*)node->schema)->child, iter = list->child;
-                    key && key->nodetype == LYS_LEAF && (key->flags & LYS_KEY) && iter;
-                    key = key->next, iter = iter->next) {
-                for ( ; iter && iter->schema != key; iter = iter->next);
-                if (!iter) {
-                    break;
-                }
-                int dynamic = 0;
-                const char *value = lyd_value2str((struct lyd_node_term *)iter, &dynamic);
+            for (iter = list->child; iter && (iter->schema->flags & LYS_KEY); iter = iter->next) {
+                const char *value = LYD_CANONICAL(iter);
                 node->hash = dict_hash_multi(node->hash, value, strlen(value));
-                if (dynamic) {
-                    free((char *)value);
-                }
             }
         } else {
             /* keyless status list */
             lyd_hash_keyless_list_dfs(list->child, &node->hash);
         }
     } else if (node->schema->nodetype == LYS_LEAFLIST) {
-        int dynamic = 0;
-        const char *value = lyd_value2str((struct lyd_node_term *)node, &dynamic);
+        const char *value = LYD_CANONICAL(node);
         node->hash = dict_hash_multi(node->hash, value, strlen(value));
-        if (dynamic) {
-            free((char*)value);
-        }
     }
     /* finish the hash */
     node->hash = dict_hash_multi(node->hash, NULL, 0);
diff --git a/src/tree_schema.h b/src/tree_schema.h
index 1f2630c..ed9bab3 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -1257,8 +1257,6 @@
 
 struct lysc_type {
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
-    struct lyd_value *dflt;          /**< type's default value if any */
-    struct lys_module *dflt_mod;     /**< module where the lysc_type::dflt value was defined (needed to correctly map prefixes). */
     struct lysc_type_plugin *plugin; /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
     uint32_t refcount;               /**< reference counter for type sharing */
@@ -1266,8 +1264,6 @@
 
 struct lysc_type_num {
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
-    struct lyd_value *dflt;          /**< type's default value if any */
-    struct lys_module *dflt_mod;     /**< module where the lysc_type::dflt value was defined (needed to correctly map prefixes). */
     struct lysc_type_plugin *plugin; /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
     uint32_t refcount;               /**< reference counter for type sharing */
@@ -1276,8 +1272,6 @@
 
 struct lysc_type_dec {
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
-    struct lyd_value *dflt;          /**< type's default value if any */
-    struct lys_module *dflt_mod;     /**< module where the lysc_type::dflt value was defined (needed to correctly map prefixes). */
     struct lysc_type_plugin *plugin; /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
     uint32_t refcount;               /**< reference counter for type sharing */
@@ -1287,8 +1281,6 @@
 
 struct lysc_type_str {
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
-    struct lyd_value *dflt;          /**< type's default value if any */
-    struct lys_module *dflt_mod;     /**< module where the lysc_type::dflt value was defined (needed to correctly map prefixes). */
     struct lysc_type_plugin *plugin; /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
     uint32_t refcount;               /**< reference counter for type sharing */
@@ -1312,8 +1304,6 @@
 
 struct lysc_type_enum {
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
-    struct lyd_value *dflt;          /**< type's default value if any */
-    struct lys_module *dflt_mod;     /**< module where the lysc_type::dflt value was defined (needed to correctly map prefixes). */
     struct lysc_type_plugin *plugin; /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
     uint32_t refcount;               /**< reference counter for type sharing */
@@ -1322,8 +1312,6 @@
 
 struct lysc_type_bits {
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
-    struct lyd_value *dflt;          /**< type's default value if any */
-    struct lys_module *dflt_mod;     /**< module where the lysc_type::dflt value was defined (needed to correctly map prefixes). */
     struct lysc_type_plugin *plugin; /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
     uint32_t refcount;               /**< reference counter for type sharing */
@@ -1333,8 +1321,6 @@
 
 struct lysc_type_leafref {
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
-    struct lyd_value *dflt;          /**< type's default value if any */
-    struct lys_module *dflt_mod;     /**< module where the lysc_type::dflt value was defined (needed to correctly map prefixes). */
     struct lysc_type_plugin *plugin; /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
     uint32_t refcount;               /**< reference counter for type sharing */
@@ -1346,8 +1332,6 @@
 
 struct lysc_type_identityref {
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
-    struct lyd_value *dflt;          /**< type's default value if any */
-    struct lys_module *dflt_mod;     /**< module where the lysc_type::dflt value was defined (needed to correctly map prefixes). */
     struct lysc_type_plugin *plugin; /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
     uint32_t refcount;               /**< reference counter for type sharing */
@@ -1357,8 +1341,6 @@
 
 struct lysc_type_instanceid {
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
-    struct lyd_value *dflt;          /**< type's default value if any */
-    struct lys_module *dflt_mod;     /**< module where the lysc_type::dflt value was defined (needed to correctly map prefixes). */
     struct lysc_type_plugin *plugin; /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
     uint32_t refcount;               /**< reference counter for type sharing */
@@ -1367,8 +1349,6 @@
 
 struct lysc_type_union {
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
-    struct lyd_value *dflt;          /**< type's default value if any */
-    struct lys_module *dflt_mod;     /**< module where the lysc_type::dflt value was defined (needed to correctly map prefixes). */
     struct lysc_type_plugin *plugin; /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
     uint32_t refcount;               /**< reference counter for type sharing */
@@ -1377,8 +1357,6 @@
 
 struct lysc_type_bin {
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
-    struct lyd_value *dflt;          /**< type's default value if any */
-    struct lys_module *dflt_mod;     /**< module where the lysc_type::dflt value was defined (needed to correctly map prefixes). */
     struct lysc_type_plugin *plugin; /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
     uint32_t refcount;               /**< reference counter for type sharing */
@@ -1567,7 +1545,6 @@
 
     const char *units;               /**< units of the leaf's type */
     struct lyd_value *dflt;          /**< default value */
-    struct lys_module *dflt_mod;     /**< module where the lysc_node_leaf::dflt value was defined (needed to correctly map prefixes). */
 };
 
 struct lysc_node_leaflist {
@@ -1595,8 +1572,7 @@
 
     const char *units;               /**< units of the leaf's type */
     struct lyd_value **dflts;        /**< list ([sized array](@ref sizedarrays)) of default values */
-    struct lys_module **dflts_mods;  /**< list ([sized array](@ref sizedarrays)) of modules where the lysc_node_leaflist::dflts values were defined
-                                          (needed to correctly map prefixes). */
+
     uint32_t min;                    /**< min-elements constraint */
     uint32_t max;                    /**< max-elements constraint */
 
diff --git a/src/tree_schema_compile.c b/src/tree_schema_compile.c
index e5cced0..4da547d 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -148,23 +148,64 @@
     return NULL;
 }
 
+static LY_ERR
+lysc_incomplete_leaf_dflt_add(struct lysc_ctx *ctx, struct lysc_node_leaf *leaf, const char *dflt,
+                              struct lys_module *dflt_mod)
+{
+    struct lysc_incomplete_dflt *r;
+    uint32_t i;
+
+    for (i = 0; i < ctx->dflts.count; ++i) {
+        r = (struct lysc_incomplete_dflt *)ctx->dflts.objs[i];
+        if (r->leaf == leaf) {
+            /* just replace the default */
+            r->dflt = dflt;
+            return LY_SUCCESS;
+        }
+    }
+
+    r = malloc(sizeof *r);
+    LY_CHECK_ERR_RET(!r, LOGMEM(ctx->ctx), LY_EMEM);
+    r->leaf = leaf;
+    r->dflt = dflt;
+    r->dflts = NULL;
+    r->dflt_mod = dflt_mod;
+    ly_set_add(&ctx->dflts, r, LY_SET_OPT_USEASLIST);
+
+    return LY_SUCCESS;
+}
+
 /**
  * @brief Add record into the compile context's list of incomplete default values.
  * @param[in] ctx Compile context with the incomplete default values list.
- * @param[in] context_node Context schema node to store in the record.
- * @param[in] dflt Incomplete default value to store in the record.
+ * @param[in] term Term context node with the default value.
+ * @param[in] value String default value.
+ * @param[in] val_len Length of @p value.
  * @param[in] dflt_mod Module of the default value definition to store in the record.
  * @return LY_EMEM in case of memory allocation failure.
  * @return LY_SUCCESS
  */
 static LY_ERR
-lysc_incomplete_dflts_add(struct lysc_ctx *ctx, struct lysc_node *context_node, struct lyd_value *dflt, struct lys_module *dflt_mod)
+lysc_incomplete_llist_dflts_add(struct lysc_ctx *ctx, struct lysc_node_leaflist *llist, const char **dflts,
+                                struct lys_module *dflt_mod)
 {
     struct lysc_incomplete_dflt *r;
+    uint32_t i;
+
+    for (i = 0; i < ctx->dflts.count; ++i) {
+        r = (struct lysc_incomplete_dflt *)ctx->dflts.objs[i];
+        if (r->llist == llist) {
+            /* just replace the defaults */
+            r->dflts = dflts;
+            return LY_SUCCESS;
+        }
+    }
+
     r = malloc(sizeof *r);
     LY_CHECK_ERR_RET(!r, LOGMEM(ctx->ctx), LY_EMEM);
-    r->context_node = context_node;
-    r->dflt = dflt;
+    r->llist = llist;
+    r->dflt = NULL;
+    r->dflts = dflts;
     r->dflt_mod = dflt_mod;
     ly_set_add(&ctx->dflts, r, LY_SET_OPT_USEASLIST);
 
@@ -177,14 +218,14 @@
  * @param[in] dflt Incomplete default values identifying the record to remove.
  */
 static void
-lysc_incomplete_dflts_remove(struct lysc_ctx *ctx, struct lyd_value *dflt)
+lysc_incomplete_dflt_remove(struct lysc_ctx *ctx, struct lysc_node *term)
 {
-    unsigned int u;
+    uint32_t u;
     struct lysc_incomplete_dflt *r;
 
     for (u = 0; u < ctx->dflts.count; ++u) {
-        r = (struct lysc_incomplete_dflt*)ctx->dflts.objs[u];
-        if (r->dflt == dflt) {
+        r = ctx->dflts.objs[u];
+        if (r->leaf == (struct lysc_node_leaf *)term) {
             free(ctx->dflts.objs[u]);
             memmove(&ctx->dflts.objs[u], &ctx->dflts.objs[u + 1], (ctx->dflts.count - (u + 1)) * sizeof *ctx->dflts.objs);
             --ctx->dflts.count;
@@ -2467,7 +2508,7 @@
 
 static LY_ERR lys_compile_type(struct lysc_ctx *ctx, struct lysp_node *context_node_p, uint16_t context_flags,
                                struct lysp_module *context_mod, const char *context_name, struct lysp_type *type_p,
-                               struct lysc_type **type, const char **units);
+                               struct lysc_type **type, const char **units, const char **dflt, struct lys_module **dflt_mod);
 
 /**
  * @brief The core of the lys_compile_type() - compile information about the given type (from typedef or leaf/leaf-list).
@@ -2791,7 +2832,7 @@
             LY_ARRAY_CREATE_RET(ctx->ctx, un->types, LY_ARRAY_COUNT(type_p->types), LY_EVALID);
             for (LY_ARRAY_COUNT_TYPE u = 0, additional = 0; u < LY_ARRAY_COUNT(type_p->types); ++u) {
                 LY_CHECK_RET(lys_compile_type(ctx, context_node_p, context_flags, context_mod, context_name,
-                                              &type_p->types[u], &un->types[u + additional], NULL));
+                                              &type_p->types[u], &un->types[u + additional], NULL, NULL, NULL));
                 if (un->types[u + additional]->basetype == LY_TYPE_UNION) {
                     /* add space for additional types from the union subtype */
                     un_aux = (struct lysc_type_union *)un->types[u + additional];
@@ -2868,12 +2909,14 @@
  * @param[in] type_p Parsed type to compile.
  * @param[out] type Newly created (or reused with increased refcount) type structure with the filled information about the type.
  * @param[out] units Storage for inheriting units value from the typedefs the current type derives from.
+ * @param[out] dflt Default value for the type.
+ * @param[out] dflt_mod Local module for the default value.
  * @return LY_ERR value.
  */
 static LY_ERR
 lys_compile_type(struct lysc_ctx *ctx, struct lysp_node *context_node_p, uint16_t context_flags,
                  struct lysp_module *context_mod, const char *context_name, struct lysp_type *type_p,
-                 struct lysc_type **type, const char **units)
+                 struct lysc_type **type, const char **units, const char **dflt, struct lys_module **dflt_mod)
 {
     LY_ERR ret = LY_SUCCESS;
     unsigned int u;
@@ -2886,10 +2929,14 @@
     LY_DATA_TYPE basetype = LY_TYPE_UNKNOWN;
     struct lysc_type *base = NULL, *prev_type;
     struct ly_set tpdf_chain = {0};
-    const char *dflt = NULL;
-    struct lys_module *dflt_mod = NULL;
+
+    assert((dflt && dflt_mod) || (!dflt && !dflt_mod));
 
     (*type) = NULL;
+    if (dflt) {
+        *dflt = NULL;
+        *dflt_mod = NULL;
+    }
 
     tctx = calloc(1, sizeof *tctx);
     LY_CHECK_ERR_RET(!tctx, LOGMEM(ctx->ctx), LY_EMEM);
@@ -2911,12 +2958,12 @@
             /* inherit units */
             DUP_STRING(ctx->ctx, tctx->tpdf->units, *units);
         }
-        if (!dflt) {
+        if (dflt && !*dflt) {
             /* inherit default */
-            dflt = tctx->tpdf->dflt;
-            dflt_mod = tctx->mod->mod;
+            *dflt = tctx->tpdf->dflt;
+            *dflt_mod = tctx->mod->mod;
         }
-        if (dummyloops && (!units || *units) && dflt) {
+        if (dummyloops && (!units || *units) && dflt && *dflt) {
             basetype = ((struct type_context*)tpdf_chain.objs[tpdf_chain.count - 1])->tpdf->type.compiled->basetype;
             break;
         }
@@ -2926,7 +2973,7 @@
              * but we still may need to inherit default and units values, so start dummy loops */
             basetype = tctx->tpdf->type.compiled->basetype;
             ly_set_add(&tpdf_chain, tctx, LY_SET_OPT_USEASLIST);
-            if ((units && !*units) || !dflt) {
+            if ((units && !*units) || (dflt && !*dflt)) {
                 dummyloops = 1;
                 goto preparenext;
             } else {
@@ -3088,29 +3135,6 @@
         (*type) = base;
         ++(*type)->refcount;
     }
-    if (dflt && !(*type)->dflt) {
-        struct ly_err_item *err = NULL;
-        (*type)->dflt_mod = dflt_mod;
-        (*type)->dflt = calloc(1, sizeof *(*type)->dflt);
-        (*type)->dflt->realtype = (*type);
-        ret = (*type)->plugin->store(ctx->ctx, (*type), dflt, strlen(dflt),
-                                     LY_TYPE_OPTS_INCOMPLETE_DATA | LY_TYPE_OPTS_SCHEMA | LY_TYPE_OPTS_STORE,
-                                     LY_PREF_SCHEMA, (*type)->dflt_mod, NULL, NULL, (*type)->dflt, NULL, &err);
-        if (err) {
-            ly_err_print(err);
-            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
-                   "Invalid type's default value \"%s\" which does not fit the type (%s).", dflt, err->msg);
-            ly_err_free(err);
-        }
-        if (ret == LY_EINCOMPLETE) {
-            /* postpone default compilation when the tree is complete */
-            LY_CHECK_GOTO(lysc_incomplete_dflts_add(ctx, NULL, (*type)->dflt, (*type)->dflt_mod), cleanup);
-
-            /* but in general result is so far ok */
-            ret = LY_SUCCESS;
-        }
-        LY_CHECK_GOTO(ret, cleanup);
-    }
 
     COMPILE_EXTS_GOTO(ctx, type_p->exts, (*type)->exts, (*type), LYEXT_PAR_TYPE, ret, cleanup);
 
@@ -3438,39 +3462,27 @@
  * @return LY_ERR value.
  */
 static LY_ERR
-lys_compile_node_type(struct lysc_ctx *ctx, struct lysp_node *context_node, struct lysp_type *type_p, struct lysc_node_leaf *leaf)
+lys_compile_node_type(struct lysc_ctx *ctx, struct lysp_node *context_node, struct lysp_type *type_p,
+                      struct lysc_node_leaf *leaf)
 {
-    struct lysc_node_leaflist *llist = (struct lysc_node_leaflist*)leaf;
+    const char *dflt;
+    struct lys_module *dflt_mod;
 
     LY_CHECK_RET(lys_compile_type(ctx, context_node, leaf->flags, ctx->mod_def->parsed, leaf->name, type_p, &leaf->type,
-                                  leaf->units ? NULL : &leaf->units));
-    if (leaf->nodetype == LYS_LEAFLIST) {
-        if (llist->type->dflt && !llist->dflts && !llist->min) {
-            LY_ARRAY_CREATE_RET(ctx->ctx, llist->dflts_mods, 1, LY_EMEM);
-            llist->dflts_mods[0] = llist->type->dflt_mod;
-            LY_ARRAY_CREATE_RET(ctx->ctx, llist->dflts, 1, LY_EMEM);
-            llist->dflts[0] = calloc(1, sizeof *llist->dflts[0]);
-            llist->dflts[0]->realtype = llist->type->dflt->realtype;
-            llist->dflts[0]->realtype->plugin->duplicate(ctx->ctx, llist->type->dflt, llist->dflts[0]);
-            llist->dflts[0]->realtype->refcount++;
-            LY_ARRAY_INCREMENT(llist->dflts);
-        }
-    } else {
-        if (leaf->type->dflt && !leaf->dflt && !(leaf->flags & LYS_MAND_TRUE)) {
-            leaf->dflt_mod = leaf->type->dflt_mod;
-            leaf->dflt = calloc(1, sizeof *leaf->dflt);
-            leaf->dflt->realtype = leaf->type->dflt->realtype;
-            leaf->dflt->realtype->plugin->duplicate(ctx->ctx, leaf->type->dflt, leaf->dflt);
-            leaf->dflt->realtype->refcount++;
-        }
+                                  leaf->units ? NULL : &leaf->units, &dflt, &dflt_mod));
+
+    /* store default value, if any */
+    if (dflt && !(leaf->flags & LYS_SET_DFLT)) {
+        LY_CHECK_RET(lysc_incomplete_leaf_dflt_add(ctx, leaf, dflt, dflt_mod));
     }
+
     if (leaf->type->basetype == LY_TYPE_LEAFREF) {
         /* store to validate the path in the current context at the end of schema compiling when all the nodes are present */
         ly_set_add(&ctx->leafrefs, leaf, 0);
     } else if (leaf->type->basetype == LY_TYPE_UNION) {
         LY_ARRAY_COUNT_TYPE u;
-        LY_ARRAY_FOR(((struct lysc_type_union*)leaf->type)->types, u) {
-            if (((struct lysc_type_union*)leaf->type)->types[u]->basetype == LY_TYPE_LEAFREF) {
+        LY_ARRAY_FOR(((struct lysc_type_union *)leaf->type)->types, u) {
+            if (((struct lysc_type_union *)leaf->type)->types[u]->basetype == LY_TYPE_LEAFREF) {
                 /* store to validate the path in the current context at the end of schema compiling when all the nodes are present */
                 ly_set_add(&ctx->leafrefs, leaf, 0);
             }
@@ -3512,41 +3524,15 @@
         leaf->flags |= LYS_SET_UNITS;
     }
 
-    /* the dflt member is just filled to avoid getting the default value from the type */
-    leaf->dflt = (void*)leaf_p->dflt;
-    ret = lys_compile_node_type(ctx, node_p, &leaf_p->type, leaf);
-    if (ret) {
-        leaf->dflt = NULL;
-        return ret;
-    }
+    /* compile type */
+    LY_CHECK_RET(lys_compile_node_type(ctx, node_p, &leaf_p->type, leaf));
 
+    /* store/update default value */
     if (leaf_p->dflt) {
-        struct ly_err_item *err = NULL;
-        leaf->dflt_mod = ctx->mod_def;
-        leaf->dflt = calloc(1, sizeof *leaf->dflt);
-        leaf->dflt->realtype = leaf->type;
-        ret = leaf->type->plugin->store(ctx->ctx, leaf->type, leaf_p->dflt, strlen(leaf_p->dflt),
-                                        LY_TYPE_OPTS_INCOMPLETE_DATA | LY_TYPE_OPTS_SCHEMA | LY_TYPE_OPTS_STORE,
-                                        LY_PREF_SCHEMA, leaf->dflt_mod, node, NULL, leaf->dflt, NULL, &err);
-        leaf->dflt->realtype->refcount++;
-        if (err) {
-            ly_err_print(err);
-            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
-                   "Invalid leaf's default value \"%s\" which does not fit the type (%s).", leaf_p->dflt, err->msg);
-            ly_err_free(err);
-        }
-        if (ret == LY_EINCOMPLETE) {
-            /* postpone default compilation when the tree is complete */
-            LY_CHECK_RET(lysc_incomplete_dflts_add(ctx, node, leaf->dflt, leaf->dflt_mod));
-
-            /* but in general result is so far ok */
-            ret = LY_SUCCESS;
-        }
-        LY_CHECK_RET(ret);
+        LY_CHECK_RET(lysc_incomplete_leaf_dflt_add(ctx, leaf, leaf_p->dflt, ctx->mod_def));
         leaf->flags |= LYS_SET_DFLT;
     }
 
-
 done:
     return ret;
 }
@@ -3564,7 +3550,7 @@
 {
     struct lysp_node_leaflist *llist_p = (struct lysp_node_leaflist*)node_p;
     struct lysc_node_leaflist *llist = (struct lysc_node_leaflist*)node;
-    LY_ARRAY_COUNT_TYPE u, v;
+    LY_ARRAY_COUNT_TYPE u;
     LY_ERR ret = LY_SUCCESS;
 
     COMPILE_ARRAY_GOTO(ctx, llist_p->musts, llist->musts, u, lys_compile_must, ret, done);
@@ -3577,69 +3563,14 @@
         llist->flags |= LYS_SET_UNITS;
     }
 
-    /* the dflts member is just filled to avoid getting the default value from the type */
-    llist->dflts = (void*)llist_p->dflts;
-    ret = lys_compile_node_type(ctx, node_p, &llist_p->type, (struct lysc_node_leaf*)llist);
-    if (ret != LY_SUCCESS) {
-        /* make sure the defaults are freed correctly */
-        if (llist_p->dflts) {
-            llist->dflts = NULL;
-        }
-        return ret;
-    }
+    /* compile type */
+    LY_CHECK_RET(lys_compile_node_type(ctx, node_p, &llist_p->type, (struct lysc_node_leaf *)llist));
 
+    /* store/update default values */
     if (llist_p->dflts) {
-        llist->dflts = NULL; /* reset the temporary llist_p->dflts */
-        LY_ARRAY_CREATE_GOTO(ctx->ctx, llist->dflts_mods, LY_ARRAY_COUNT(llist_p->dflts), ret, done);
-        LY_ARRAY_CREATE_GOTO(ctx->ctx, llist->dflts, LY_ARRAY_COUNT(llist_p->dflts), ret, done);
-        LY_ARRAY_FOR(llist_p->dflts, u) {
-            struct ly_err_item *err = NULL;
-            LY_ARRAY_INCREMENT(llist->dflts_mods);
-            llist->dflts_mods[u] = ctx->mod_def;
-            LY_ARRAY_INCREMENT(llist->dflts);
-            llist->dflts[u] = calloc(1, sizeof *llist->dflts[u]);
-            llist->dflts[u]->realtype = llist->type;
-            ret = llist->type->plugin->store(ctx->ctx, llist->type, llist_p->dflts[u], strlen(llist_p->dflts[u]),
-                                             LY_TYPE_OPTS_INCOMPLETE_DATA | LY_TYPE_OPTS_SCHEMA | LY_TYPE_OPTS_STORE,
-                                             LY_PREF_SCHEMA, llist->dflts_mods[u], node, NULL, llist->dflts[u], NULL, &err);
-            llist->dflts[u]->realtype->refcount++;
-            if (err) {
-                ly_err_print(err);
-                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
-                       "Invalid leaf-lists's default value \"%s\" which does not fit the type (%s).", llist_p->dflts[u], err->msg);
-                ly_err_free(err);
-            }
-            if (ret == LY_EINCOMPLETE) {
-                /* postpone default compilation when the tree is complete */
-                LY_CHECK_GOTO(lysc_incomplete_dflts_add(ctx, node, llist->dflts[u], llist->dflts_mods[u]), done);
-
-                /* but in general result is so far ok */
-                ret = LY_SUCCESS;
-            }
-            LY_CHECK_GOTO(ret, done);
-        }
+        LY_CHECK_GOTO(lysc_incomplete_llist_dflts_add(ctx, llist, llist_p->dflts, ctx->mod_def), done);
         llist->flags |= LYS_SET_DFLT;
     }
-    if ((llist->flags & LYS_CONFIG_W) && llist->dflts && LY_ARRAY_COUNT(llist->dflts)) {
-        /* configuration data values must be unique - so check the default values */
-        LY_ARRAY_FOR(llist->dflts, u) {
-            for (v = u + 1; v < LY_ARRAY_COUNT(llist->dflts); ++v) {
-                if (!llist->type->plugin->compare(llist->dflts[u], llist->dflts[v])) {
-                    int dynamic = 0;
-                    const char *val = llist->type->plugin->print(llist->dflts[v], LY_PREF_SCHEMA, llist->dflts_mods[v],
-                                                                 &dynamic);
-                    LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
-                           "Configuration leaf-list has multiple defaults of the same value \"%s\".", val);
-                    if (dynamic) {
-                        free((char*)val);
-                    }
-                    return LY_EVALID;
-                }
-            }
-        }
-    }
-
-    /* TODO validate default value according to the type, possibly postpone the check when the leafref target is known */
 
     llist->min = llist_p->min;
     if (llist->min) {
@@ -3852,7 +3783,6 @@
             lysc_type_free(ctx->ctx, key->dflt->realtype);
             free(key->dflt);
             key->dflt = NULL;
-            key->dflt_mod = NULL;
         }
         /* mark leaf as key */
         key->flags |= LYS_KEY;
@@ -4623,20 +4553,8 @@
                            "Invalid refine of mandatory - leaf already has \"default\" statement.");
                     return LY_EVALID;
                 }
-            } else if (((struct lysc_node_leaf*)node)->dflt) {
-                /* remove the default value taken from the leaf's type */
-                struct lysc_node_leaf *leaf = (struct lysc_node_leaf*)node;
-
-                /* update the list of incomplete default values if needed */
-                lysc_incomplete_dflts_remove(ctx, leaf->dflt);
-
-                leaf->dflt->realtype->plugin->free(ctx->ctx, leaf->dflt);
-                lysc_type_free(ctx->ctx, leaf->dflt->realtype);
-                free(leaf->dflt);
-                leaf->dflt = NULL;
-                leaf->dflt_mod = NULL;
             }
-        } else if ((node->nodetype & LYS_CHOICE) && ((struct lysc_node_choice*)node)->dflt) {
+        } else if ((node->nodetype & LYS_CHOICE) && ((struct lysc_node_choice *)node)->dflt) {
             if (refine_flag) {
                 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
                        "Invalid refine of mandatory - choice already has \"default\" statement.");
@@ -4656,15 +4574,6 @@
         node->flags &= ~LYS_MAND_TRUE;
         node->flags |= LYS_MAND_FALSE;
         lys_compile_mandatory_parents(node->parent, 0);
-        if ((node->nodetype & LYS_LEAF) && !((struct lysc_node_leaf*)node)->dflt && ((struct lysc_node_leaf*)node)->type->dflt) {
-            /* get the type's default value if any */
-            struct lysc_node_leaf *leaf = (struct lysc_node_leaf*)node;
-            leaf->dflt_mod = leaf->type->dflt_mod;
-            leaf->dflt = calloc(1, sizeof *leaf->dflt);
-            leaf->dflt->realtype = leaf->type->dflt->realtype;
-            leaf->dflt->realtype->plugin->duplicate(ctx->ctx, leaf->type->dflt, leaf->dflt);
-            leaf->dflt->realtype->refcount++;
-        }
     }
     return LY_SUCCESS;
 }
@@ -4701,7 +4610,7 @@
     size_t prefix_len, name_len;
     struct lys_module *mod, *mod_old;
     struct lysp_refine *rfn;
-    LY_ERR ret = LY_EVALID, rc;
+    LY_ERR ret = LY_EVALID;
     uint32_t min, max;
     uint16_t flags;
     struct ly_set refined = {0};
@@ -4917,91 +4826,21 @@
                 goto cleanup;
             }
             if (node->nodetype == LYS_LEAF) {
-                struct ly_err_item *err = NULL;
-                struct lysc_node_leaf *leaf = (struct lysc_node_leaf*)node;
-                if (leaf->dflt) {
-                    /* remove the previous default value */
-                    lysc_incomplete_dflts_remove(ctx, leaf->dflt);
-                    leaf->dflt->realtype->plugin->free(ctx->ctx, leaf->dflt);
-                    lysc_type_free(ctx->ctx, leaf->dflt->realtype);
-                } else {
-                    /* prepare a new one */
-                    leaf->dflt = calloc(1, sizeof *leaf->dflt);
-                    leaf->dflt->realtype = leaf->type;
-                }
-                /* parse the new one */
-                leaf->dflt_mod = ctx->mod_def;
-                rc = leaf->type->plugin->store(ctx->ctx, leaf->type, rfn->dflts[0], strlen(rfn->dflts[0]),
-                                                LY_TYPE_OPTS_INCOMPLETE_DATA | LY_TYPE_OPTS_SCHEMA | LY_TYPE_OPTS_STORE,
-                                                LY_PREF_SCHEMA, leaf->dflt_mod, node, NULL, leaf->dflt, NULL, &err);
-                leaf->dflt->realtype->refcount++;
-                if (err) {
-                    ly_err_print(err);
-                    LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
-                           "Invalid refine of default - value \"%s\" does not fit the type (%s).", rfn->dflts[0], err->msg);
-                    ly_err_free(err);
-                }
-                if (rc == LY_EINCOMPLETE) {
-                    /* postpone default compilation when the tree is complete */
-                    LY_CHECK_GOTO(lysc_incomplete_dflts_add(ctx, node, leaf->dflt, leaf->dflt_mod), cleanup);
-
-                    /* but in general result is so far ok */
-                    rc = LY_SUCCESS;
-                }
-                LY_CHECK_GOTO(rc, cleanup);
-                leaf->flags |= LYS_SET_DFLT;
+                /* postpone default compilation when the tree is complete */
+                LY_CHECK_GOTO(lysc_incomplete_leaf_dflt_add(ctx, (struct lysc_node_leaf *)node, rfn->dflts[0],
+                                                            ctx->mod_def), cleanup);
+                node->flags |= LYS_SET_DFLT;
             } else if (node->nodetype == LYS_LEAFLIST) {
-                struct lysc_node_leaflist *llist = (struct lysc_node_leaflist*)node;
-
                 if (ctx->mod->version < 2) {
                     LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
                            "Invalid refine of default in leaf-list - the default statement is allowed only in YANG 1.1 modules.");
                     goto cleanup;
                 }
 
-                /* remove previous set of default values */
-                LY_ARRAY_FOR(llist->dflts, u) {
-                    lysc_incomplete_dflts_remove(ctx, llist->dflts[u]);
-                    llist->dflts[u]->realtype->plugin->free(ctx->ctx, llist->dflts[u]);
-                    lysc_type_free(ctx->ctx, llist->dflts[u]->realtype);
-                    free(llist->dflts[u]);
-                }
-                LY_ARRAY_FREE(llist->dflts);
-                llist->dflts = NULL;
-                LY_ARRAY_FREE(llist->dflts_mods);
-                llist->dflts_mods = NULL;
-
-                /* create the new set of the default values */
-                LY_ARRAY_CREATE_GOTO(ctx->ctx, llist->dflts_mods, LY_ARRAY_COUNT(rfn->dflts), ret, cleanup);
-                LY_ARRAY_CREATE_GOTO(ctx->ctx, llist->dflts, LY_ARRAY_COUNT(rfn->dflts), ret, cleanup);
-                LY_ARRAY_FOR(rfn->dflts, u) {
-                    struct ly_err_item *err = NULL;
-                    LY_ARRAY_INCREMENT(llist->dflts_mods);
-                    llist->dflts_mods[u] = ctx->mod_def;
-                    LY_ARRAY_INCREMENT(llist->dflts);
-                    llist->dflts[u] = calloc(1, sizeof *llist->dflts[u]);
-                    llist->dflts[u]->realtype = llist->type;
-                    rc = llist->type->plugin->store(ctx->ctx, llist->type, rfn->dflts[u], strlen(rfn->dflts[u]),
-                                                    LY_TYPE_OPTS_INCOMPLETE_DATA | LY_TYPE_OPTS_SCHEMA | LY_TYPE_OPTS_STORE,
-                                                    LY_PREF_SCHEMA, llist->dflts_mods[u], node, NULL, llist->dflts[u],
-                                                    NULL, &err);
-                    llist->dflts[u]->realtype->refcount++;
-                    if (err) {
-                        ly_err_print(err);
-                        LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
-                               "Invalid refine of default in leaf-lists -  value \"%s\" does not fit the type (%s).", rfn->dflts[u], err->msg);
-                        ly_err_free(err);
-                    }
-                    if (rc == LY_EINCOMPLETE) {
-                        /* postpone default compilation when the tree is complete */
-                        LY_CHECK_GOTO(lysc_incomplete_dflts_add(ctx, node, llist->dflts[u], llist->dflts_mods[u]), cleanup);
-
-                        /* but in general result is so far ok */
-                        rc = LY_SUCCESS;
-                    }
-                    LY_CHECK_GOTO(rc, cleanup);
-                }
-                llist->flags |= LYS_SET_DFLT;
+                /* postpone default compilation when the tree is complete */
+                LY_CHECK_GOTO(lysc_incomplete_llist_dflts_add(ctx, (struct lysc_node_leaflist *)node, rfn->dflts,
+                                                              ctx->mod_def), cleanup);
+                node->flags |= LYS_SET_DFLT;
             } else if (node->nodetype == LYS_CHOICE) {
                 if (((struct lysc_node_choice*)node)->dflt) {
                     /* unset LYS_SET_DFLT from the current default case */
@@ -5650,18 +5489,15 @@
  * @param[in] target Deviation target.
  * @param[in] dev_flags Internal deviation flags.
  * @param[in] d Deviate add to apply.
- * @param[out] dflt Added default value.
  * @return LY_ERR value.
  */
 static LY_ERR
-lys_apply_deviate_add(struct lysc_ctx *ctx, struct lysc_node *target, int dev_flags, struct lysp_deviate_add *d,
-                      const char **dflt)
+lys_apply_deviate_add(struct lysc_ctx *ctx, struct lysc_node *target, int dev_flags, struct lysp_deviate_add *d)
 {
-    LY_ERR ret = LY_EVALID, rc;
+    LY_ERR ret = LY_EVALID;
     struct lysc_node_leaf *leaf = (struct lysc_node_leaf *)target;
     struct lysc_node_leaflist *llist = (struct lysc_node_leaflist *)target;
-    struct ly_err_item *err = NULL;
-    LY_ARRAY_COUNT_TYPE x, y;
+    LY_ARRAY_COUNT_TYPE x;
 
 #define DEV_CHECK_NONPRESENCE_UINT(TYPE, COND, MEMBER, PROPERTY) \
     if (((TYPE)target)->MEMBER COND) { \
@@ -5671,11 +5507,11 @@
         goto cleanup; \
     }
 
-#define DEV_CHECK_NONPRESENCE_VALUE(TYPE, COND, MEMBER, PROPERTY, VALUEMEMBER, VALUEMODMEMBER) \
+#define DEV_CHECK_NONPRESENCE_VALUE(TYPE, COND, MEMBER, PROPERTY, VALUEMEMBER) \
     if (((TYPE)target)->MEMBER && (COND)) { \
         int dynamic_ = 0; const char *val_; \
         val_ = ((TYPE)target)->VALUEMEMBER->realtype->plugin->print(((TYPE)target)->VALUEMEMBER, LY_PREF_SCHEMA, \
-                                                                             ((TYPE)target)->VALUEMODMEMBER, &dynamic_); \
+                                                                             ctx->mod_def, &dynamic_); \
         LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, \
                "Invalid deviation adding \"%s\" property which already exists (with value \"%s\").", PROPERTY, val_); \
         if (dynamic_) {free((void*)val_);} \
@@ -5748,67 +5584,33 @@
         switch (target->nodetype) {
         case LYS_LEAF:
             DEV_CHECK_CARDINALITY(d->dflts, 1, "default");
-            DEV_CHECK_NONPRESENCE_VALUE(struct lysc_node_leaf *, (target->flags & LYS_SET_DFLT), dflt, "default", dflt, dflt_mod);
+            DEV_CHECK_NONPRESENCE_VALUE(struct lysc_node_leaf *, (target->flags & LYS_SET_DFLT), dflt, "default", dflt);
             if (leaf->dflt) {
                 /* first, remove the default value taken from the type */
-                lysc_incomplete_dflts_remove(ctx, leaf->dflt);
                 leaf->dflt->realtype->plugin->free(ctx->ctx, leaf->dflt);
                 lysc_type_free(ctx->ctx, leaf->dflt->realtype);
-            } else {
-                /* prepare new default value storage */
-                leaf->dflt = calloc(1, sizeof *leaf->dflt);
+                free(leaf->dflt);
+                leaf->dflt = NULL;
             }
-            *dflt = d->dflts[0];
-            /* parsing is done at the end after possible replace of the leaf's type */
 
-            /* mark the new default values as leaf's own */
+            /* store the default value in unres */
+            lysc_incomplete_leaf_dflt_add(ctx, leaf, d->dflts[0], ctx->mod_def);
             target->flags |= LYS_SET_DFLT;
             break;
         case LYS_LEAFLIST:
             if (llist->dflts && !(target->flags & LYS_SET_DFLT)) {
                 /* first, remove the default value taken from the type */
                 LY_ARRAY_FOR(llist->dflts, x) {
-                    lysc_incomplete_dflts_remove(ctx, llist->dflts[x]);
                     llist->dflts[x]->realtype->plugin->free(ctx->ctx, llist->dflts[x]);
                     lysc_type_free(ctx->ctx, llist->dflts[x]->realtype);
                     free(llist->dflts[x]);
                 }
                 LY_ARRAY_FREE(llist->dflts);
                 llist->dflts = NULL;
-                LY_ARRAY_FREE(llist->dflts_mods);
-                llist->dflts_mods = NULL;
             }
-            /* add new default value(s) */
-            LY_ARRAY_CREATE_GOTO(ctx->ctx, llist->dflts_mods, LY_ARRAY_COUNT(d->dflts), ret, cleanup);
-            LY_ARRAY_CREATE_GOTO(ctx->ctx, llist->dflts, LY_ARRAY_COUNT(d->dflts), ret, cleanup);
-            for (x = y = LY_ARRAY_COUNT(llist->dflts);
-                    x < LY_ARRAY_COUNT(d->dflts) + y; ++x) {
-                LY_ARRAY_INCREMENT(llist->dflts_mods);
-                llist->dflts_mods[x] = ctx->mod_def;
-                LY_ARRAY_INCREMENT(llist->dflts);
-                llist->dflts[x] = calloc(1, sizeof *llist->dflts[x]);
-                llist->dflts[x]->realtype = llist->type;
-                rc = llist->type->plugin->store(ctx->ctx, llist->type, d->dflts[x - y], strlen(d->dflts[x - y]),
-                                                LY_TYPE_OPTS_INCOMPLETE_DATA | LY_TYPE_OPTS_SCHEMA | LY_TYPE_OPTS_STORE,
-                                                LY_PREF_SCHEMA, llist->dflts_mods[x], target, NULL, llist->dflts[x], NULL, &err);
-                llist->dflts[x]->realtype->refcount++;
-                if (err) {
-                    ly_err_print(err);
-                    LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
-                            "Invalid deviation adding \"default\" property \"%s\" which does not fit the type (%s).",
-                            d->dflts[x - y], err->msg);
-                    ly_err_free(err);
-                }
-                if (rc == LY_EINCOMPLETE) {
-                    /* postpone default compilation when the tree is complete */
-                    LY_CHECK_GOTO(lysc_incomplete_dflts_add(ctx, target, llist->dflts[x], llist->dflts_mods[x]), cleanup);
 
-                    /* but in general result is so far ok */
-                    rc = LY_SUCCESS;
-                }
-                LY_CHECK_GOTO(rc, cleanup);
-            }
-            /* mark the new default values as leaf-list's own */
+            /* store the default values in unres */
+            LY_CHECK_GOTO(lysc_incomplete_llist_dflts_add(ctx, llist, d->dflts, ctx->mod_def), cleanup);
             target->flags |= LYS_SET_DFLT;
             break;
         case LYS_CHOICE:
@@ -5901,6 +5703,164 @@
     return ret;
 }
 
+static LY_ERR
+lys_apply_deviate_delete_leaf_dflt(struct lysc_ctx *ctx, struct lysc_node *target, const char *dflt)
+{
+    struct lysc_node_leaf *leaf = (struct lysc_node_leaf *)target;
+    int dyn = 0;
+    const char *orig_dflt;
+    uint32_t i;
+
+    if (target->module != ctx->mod) {
+        /* foreign deviation */
+        DEV_CHECK_PRESENCE(struct lysc_node_leaf *, !(target->flags & LYS_SET_DFLT), dflt, "deleting", "default", dflt);
+
+        /* check that the value matches */
+        orig_dflt = leaf->dflt->realtype->plugin->print(leaf->dflt, LY_PREF_SCHEMA, ctx->mod_def, &dyn);
+        if (strcmp(orig_dflt, dflt)) {
+            goto error;
+        }
+        if (dyn) {
+            free((char *)orig_dflt);
+        }
+
+        /* remove the default specification */
+        leaf->dflt->realtype->plugin->free(ctx->ctx, leaf->dflt);
+        lysc_type_free(ctx->ctx, leaf->dflt->realtype);
+        free(leaf->dflt);
+        leaf->dflt = NULL;
+    } else {
+        /* local deviation */
+        DEV_CHECK_PRESENCE(struct lysc_node_leaf *, !(target->flags & LYS_SET_DFLT), name, "deleting", "default", dflt);
+
+        /* find the incomplete default */
+        orig_dflt = NULL;
+        for (i = 0; i < ctx->dflts.count; ++i) {
+            if (((struct lysc_incomplete_dflt *)ctx->dflts.objs[i])->leaf == leaf) {
+                orig_dflt = ((struct lysc_incomplete_dflt *)ctx->dflts.objs[i])->dflt;
+                break;
+            }
+        }
+        LY_CHECK_ERR_RET(!orig_dflt, LOGINT(ctx->ctx), LY_EINT);
+
+        /* check that the value matches */
+        if (strcmp(orig_dflt, dflt)) {
+            goto error;
+        }
+
+        /* update the list of incomplete default values */
+        lysc_incomplete_dflt_remove(ctx, target);
+    }
+
+    target->flags &= ~LYS_SET_DFLT;
+    return LY_SUCCESS;
+
+error:
+    LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+            "Invalid deviation deleting \"default\" property \"%s\" which does not match the target's property value \"%s\".",
+            dflt, orig_dflt);
+    if (dyn) {
+        free((char *)orig_dflt);
+    }
+cleanup:
+    return LY_EVALID;
+}
+
+static LY_ERR
+lys_apply_deviate_delete_llist_dflts(struct lysc_ctx *ctx, struct lysc_node *target, const char **dflts)
+{
+    struct lysc_node_leaflist *llist = (struct lysc_node_leaflist *)target;
+    int dyn = 0, found;
+    const char *orig_dflt, **orig_dflts;
+    uint32_t i;
+    LY_ARRAY_COUNT_TYPE x, y;
+
+    if (target->module != ctx->mod) {
+        /* foreign deviation */
+        DEV_CHECK_PRESENCE(struct lysc_node_leaflist *, 0, dflts, "deleting", "default", dflts[0]);
+        LY_ARRAY_FOR(dflts, x) {
+            found = 0;
+            LY_ARRAY_FOR(llist->dflts, y) {
+                orig_dflt = llist->type->plugin->print(llist->dflts[y], LY_PREF_SCHEMA, ctx->mod_def, &dyn);
+                if (!strcmp(orig_dflt, dflts[x])) {
+                    if (dyn) {
+                        free((char *)orig_dflt);
+                    }
+                    found = 1;
+                    break;
+                }
+                if (dyn) {
+                    free((char *)orig_dflt);
+                }
+            }
+            if (!found) {
+                goto error;
+            }
+
+            /* update compiled default values */
+            LY_ARRAY_DECREMENT(llist->dflts);
+            llist->dflts[y]->realtype->plugin->free(ctx->ctx, llist->dflts[y]);
+            lysc_type_free(ctx->ctx, llist->dflts[y]->realtype);
+            free(llist->dflts[y]);
+            memmove(&llist->dflts[y], &llist->dflts[y + 1], (LY_ARRAY_COUNT(llist->dflts) - y) * (sizeof *llist->dflts));
+        }
+        if (!LY_ARRAY_COUNT(llist->dflts)) {
+            LY_ARRAY_FREE(llist->dflts);
+            llist->dflts = NULL;
+            llist->flags &= ~LYS_SET_DFLT;
+        }
+    } else {
+        /* local deviation */
+        orig_dflt = NULL;
+        orig_dflts = NULL;
+        for (i = 0; i < ctx->dflts.count; ++i) {
+            if (((struct lysc_incomplete_dflt *)ctx->dflts.objs[i])->llist == llist) {
+                orig_dflt = ((struct lysc_incomplete_dflt *)ctx->dflts.objs[i])->dflt;
+                orig_dflts = ((struct lysc_incomplete_dflt *)ctx->dflts.objs[i])->dflts;
+                break;
+            }
+        }
+        LY_CHECK_ERR_RET(!orig_dflt && !orig_dflts, LOGINT(ctx->ctx), LY_EINT);
+
+        if (orig_dflts && (LY_ARRAY_COUNT(orig_dflts) > 1)) {
+            /* TODO it is not currently possible to remove just one default value from incomplete defaults array */
+            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+                "Local deviation deleting leaf-list defaults is not supported.");
+            return LY_EVALID;
+        }
+
+        LY_ARRAY_FOR(dflts, x) {
+            found = 0;
+            if (orig_dflts) {
+                LY_ARRAY_FOR(orig_dflts, y) {
+                    if (!strcmp(orig_dflts[y], dflts[x])) {
+                        found = 1;
+                        break;
+                    }
+                }
+            } else if (!strcmp(orig_dflt, dflts[x])) {
+                found = 1;
+            }
+            if (!found) {
+                goto error;
+            }
+
+            /* update the list of incomplete default values */
+            lysc_incomplete_dflt_remove(ctx, target);
+        }
+
+        llist->flags &= ~LYS_SET_DFLT;
+    }
+
+    return LY_SUCCESS;
+
+error:
+    LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, "Invalid deviation deleting \"default\" property \"%s\" "
+                "which does not match any of the target's property values.", dflts[x]);
+cleanup:
+    return LY_EVALID;
+}
+
 /**
  * @brief Apply deviate delete.
  *
@@ -5914,13 +5874,10 @@
 lys_apply_deviate_delete(struct lysc_ctx *ctx, struct lysc_node *target, int dev_flags, struct lysp_deviate_del *d)
 {
     LY_ERR ret = LY_EVALID;
-    struct lysc_node_leaf *leaf = (struct lysc_node_leaf *)target;
-    struct lysc_node_leaflist *llist = (struct lysc_node_leaflist *)target;
     struct lysc_node_list *list = (struct lysc_node_list *)target;
     LY_ARRAY_COUNT_TYPE x, y, z;
-    int i;
     size_t prefix_len, name_len;
-    const char *prefix, *name, *nodeid, *dflt;
+    const char *prefix, *name, *nodeid;
     struct lys_module *mod;
 
 #define DEV_DEL_ARRAY(TYPE, ARRAY_TRG, ARRAY_DEV, VALMEMBER, VALMEMBER_CMP, DELFUNC_DEREF, DELFUNC, PROPERTY) \
@@ -6039,74 +5996,10 @@
         switch (target->nodetype) {
         case LYS_LEAF:
             DEV_CHECK_CARDINALITY(d->dflts, 1, "default");
-            DEV_CHECK_PRESENCE(struct lysc_node_leaf*, !(target->flags & LYS_SET_DFLT),
-                                dflt, "deleting", "default", d->dflts[0]);
-
-            /* check that the values matches */
-            dflt = leaf->dflt->realtype->plugin->print(leaf->dflt, LY_PREF_SCHEMA, leaf->dflt_mod, &i);
-            if (strcmp(dflt, d->dflts[0])) {
-                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
-                        "Invalid deviation deleting \"default\" property \"%s\" which does not match the target's property value \"%s\".",
-                        d->dflts[0], dflt);
-                if (i) {
-                    free((char*)dflt);
-                }
-                goto cleanup;
-            }
-            if (i) {
-                free((char*)dflt);
-            }
-
-            /* update the list of incomplete default values if needed */
-            lysc_incomplete_dflts_remove(ctx, leaf->dflt);
-
-            /* remove the default specification */
-            leaf->dflt->realtype->plugin->free(ctx->ctx, leaf->dflt);
-            lysc_type_free(ctx->ctx, leaf->dflt->realtype);
-            free(leaf->dflt);
-            leaf->dflt = NULL;
-            leaf->dflt_mod = NULL;
-            target->flags &= ~LYS_SET_DFLT;
+            LY_CHECK_GOTO(lys_apply_deviate_delete_leaf_dflt(ctx, target, d->dflts[0]), cleanup);
             break;
         case LYS_LEAFLIST:
-            DEV_CHECK_PRESENCE(struct lysc_node_leaflist*, 0, dflts, "deleting", "default", d->dflts[0]);
-            LY_ARRAY_FOR(d->dflts, x) {
-                LY_ARRAY_FOR(llist->dflts, y) {
-                    dflt = llist->type->plugin->print(llist->dflts[y], LY_PREF_SCHEMA, llist->dflts_mods[y], &i);
-                    if (!strcmp(dflt, d->dflts[x])) {
-                        if (i) {
-                            free((char*)dflt);
-                        }
-                        break;
-                    }
-                    if (i) {
-                        free((char*)dflt);
-                    }
-                }
-                if (y == LY_ARRAY_COUNT(llist->dflts)) {
-                    LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, "Invalid deviation deleting \"default\" property \"%s\" "
-                            "which does not match any of the target's property values.", d->dflts[x]);
-                    goto cleanup;
-                }
-
-                /* update the list of incomplete default values if needed */
-                lysc_incomplete_dflts_remove(ctx, llist->dflts[y]);
-
-                LY_ARRAY_DECREMENT(llist->dflts_mods);
-                LY_ARRAY_DECREMENT(llist->dflts);
-                llist->dflts[y]->realtype->plugin->free(ctx->ctx, llist->dflts[y]);
-                lysc_type_free(ctx->ctx, llist->dflts[y]->realtype);
-                free(llist->dflts[y]);
-                memmove(&llist->dflts[y], &llist->dflts[y + 1], (LY_ARRAY_COUNT(llist->dflts) - y) * (sizeof *llist->dflts));
-                memmove(&llist->dflts_mods[y], &llist->dflts_mods[y + 1], (LY_ARRAY_COUNT(llist->dflts_mods) - y) * (sizeof *llist->dflts_mods));
-            }
-            if (!LY_ARRAY_COUNT(llist->dflts)) {
-                LY_ARRAY_FREE(llist->dflts_mods);
-                llist->dflts_mods = NULL;
-                LY_ARRAY_FREE(llist->dflts);
-                llist->dflts = NULL;
-                llist->flags &= ~LYS_SET_DFLT;
-            }
+            LY_CHECK_GOTO(lys_apply_deviate_delete_llist_dflts(ctx, target, d->dflts), cleanup);
             break;
         case LYS_CHOICE:
             DEV_CHECK_CARDINALITY(d->dflts, 1, "default");
@@ -6154,19 +6047,83 @@
     return ret;
 }
 
+static LY_ERR
+lys_apply_deviate_replace_dflt_recompile(struct lysc_ctx *ctx, struct lysc_node *target)
+{
+    LY_ERR ret;
+    struct lysc_node_leaf *leaf = (struct lysc_node_leaf *)target;
+    struct lysc_node_leaflist *llist = (struct lysc_node_leaflist *)target;
+    struct ly_err_item *err = NULL;
+    LY_ARRAY_COUNT_TYPE x;
+    const char *dflt;
+    int dyn;
+
+    if (target->module != ctx->mod) {
+        /* foreign deviation */
+        if (target->nodetype == LYS_LEAF) {
+            dflt = leaf->dflt->realtype->plugin->print(leaf->dflt, LY_PREF_JSON, NULL, &dyn);
+            leaf->dflt->realtype->plugin->free(ctx->ctx, leaf->dflt);
+            lysc_type_free(ctx->ctx, leaf->dflt->realtype);
+
+            ret = leaf->type->plugin->store(ctx->ctx, leaf->type, dflt, strlen(dflt), LY_TYPE_OPTS_SCHEMA,
+                                            LY_PREF_JSON, NULL, target, NULL, leaf->dflt, &err);
+            if (dyn) {
+                free((char *)dflt);
+            }
+            if (err) {
+                ly_err_print(err);
+                ctx->path[0] = '\0';
+                lysc_path(target, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
+                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+                    "Invalid default - value does not fit the type (%s).", err->msg);
+                ly_err_free(err);
+            }
+            LY_CHECK_RET(ret);
+
+            ++leaf->dflt->realtype->refcount;
+        } else { /* LY_LEAFLIST */
+            LY_ARRAY_FOR(llist->dflts, x) {
+                dflt = llist->dflts[x]->realtype->plugin->print(llist->dflts[x], LY_PREF_JSON, NULL, &dyn);
+                llist->dflts[x]->realtype->plugin->free(ctx->ctx, llist->dflts[x]);
+                lysc_type_free(ctx->ctx, llist->dflts[x]->realtype);
+
+                ret = llist->type->plugin->store(ctx->ctx, llist->type, dflt, strlen(dflt), LY_TYPE_OPTS_SCHEMA,
+                                                 LY_PREF_JSON, NULL, target, NULL, llist->dflts[x], &err);
+                if (dyn) {
+                    free((char *)dflt);
+                }
+                if (err) {
+                    ly_err_print(err);
+                    ctx->path[0] = '\0';
+                    lysc_path(target, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
+                    LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+                        "Invalid default - value does not fit the type (%s).", err->msg);
+                    ly_err_free(err);
+                }
+                LY_CHECK_RET(ret);
+
+                ++llist->dflts[x]->realtype->refcount;
+            }
+        }
+    } else {
+        /* local deviation */
+
+        /* these default were not compiled yet, so they will use the new type automatically */
+    }
+
+    return LY_SUCCESS;
+}
+
 /**
  * @brief Apply deviate replace.
  *
  * @param[in] ctx Compile context.
  * @param[in] target Deviation target.
  * @param[in] d Deviate replace to apply.
- * @param[out] dflt Added default value.
- * @param[out] changed_type Whether the target type was changed.
  * @return LY_ERR value.
  */
 static LY_ERR
-lys_apply_deviate_replace(struct lysc_ctx *ctx, struct lysc_node *target, struct lysp_deviate_rpl *d, const char **dflt,
-                          int *changed_type)
+lys_apply_deviate_replace(struct lysc_ctx *ctx, struct lysc_node *target, struct lysp_deviate_rpl *d)
 {
     LY_ERR ret = LY_EVALID;
     struct lysc_node_leaf *leaf = (struct lysc_node_leaf *)target;
@@ -6186,37 +6143,36 @@
         /* type is mandatory, so checking for its presence is not necessary */
         lysc_type_free(ctx->ctx, ((struct lysc_node_leaf *)target)->type);
 
-        if (leaf->dflt && !(target->flags & LYS_SET_DFLT)) {
-            /* the target has default from the previous type - remove it */
-            if (target->nodetype == LYS_LEAF) {
-                /* update the list of incomplete default values if needed */
-                lysc_incomplete_dflts_remove(ctx, leaf->dflt);
-
-                leaf->dflt->realtype->plugin->free(ctx->ctx, leaf->dflt);
-                lysc_type_free(ctx->ctx, leaf->dflt->realtype);
-                free(leaf->dflt);
-                leaf->dflt = NULL;
-                leaf->dflt_mod = NULL;
-            } else { /* LYS_LEAFLIST */
-                LY_ARRAY_FOR(llist->dflts, x) {
-                    lysc_incomplete_dflts_remove(ctx, llist->dflts[x]);
-                    llist->dflts[x]->realtype->plugin->free(ctx->ctx, llist->dflts[x]);
-                    lysc_type_free(ctx->ctx, llist->dflts[x]->realtype);
-                    free(llist->dflts[x]);
+        /* remove only default value inherited from the type */
+        if (!(target->flags & LYS_SET_DFLT)) {
+            if (target->module != ctx->mod) {
+                /* foreign deviation - the target has default from the previous type, remove it */
+                if (target->nodetype == LYS_LEAF) {
+                    leaf->dflt->realtype->plugin->free(ctx->ctx, leaf->dflt);
+                    lysc_type_free(ctx->ctx, leaf->dflt->realtype);
+                    free(leaf->dflt);
+                    leaf->dflt = NULL;
+                } else { /* LYS_LEAFLIST */
+                    LY_ARRAY_FOR(llist->dflts, x) {
+                        llist->dflts[x]->realtype->plugin->free(ctx->ctx, llist->dflts[x]);
+                        lysc_type_free(ctx->ctx, llist->dflts[x]->realtype);
+                        free(llist->dflts[x]);
+                    }
+                    LY_ARRAY_FREE(llist->dflts);
+                    llist->dflts = NULL;
                 }
-                LY_ARRAY_FREE(llist->dflts);
-                llist->dflts = NULL;
-                LY_ARRAY_FREE(llist->dflts_mods);
-                llist->dflts_mods = NULL;
+            } else {
+                /* local deviation */
+                lysc_incomplete_dflt_remove(ctx, target);
             }
         }
-        if (!leaf->dflt) {
-            /* there is no default value, do not set changed_type after type compilation
-             * which is used to recompile the default value */
-            *changed_type = -1;
+
+        LY_CHECK_RET(lys_compile_node_type(ctx, NULL, d->type, leaf));
+
+        if (target->flags & LYS_SET_DFLT) {
+            /* the term default value(s) needs to be recompiled */
+            LY_CHECK_RET(lys_apply_deviate_replace_dflt_recompile(ctx, target));
         }
-        LY_CHECK_GOTO(lys_compile_node_type(ctx, NULL, d->type, leaf), cleanup);
-        (*changed_type)++;
     }
 
     /* [units-stmt] */
@@ -6233,14 +6189,25 @@
     if (d->dflt) {
         switch (target->nodetype) {
         case LYS_LEAF:
-            DEV_CHECK_PRESENCE(struct lysc_node_leaf *, !(target->flags & LYS_SET_DFLT),
-                                dflt, "replacing", "default", d->dflt);
-            /* first, remove the default value taken from the type */
-            lysc_incomplete_dflts_remove(ctx, leaf->dflt);
-            leaf->dflt->realtype->plugin->free(ctx->ctx, leaf->dflt);
-            lysc_type_free(ctx->ctx, leaf->dflt->realtype);
-            *dflt = d->dflt;
-            /* parsing is done at the end after possible replace of the leaf's type */
+            if (target->module != ctx->mod) {
+                /* foreign deviation */
+                DEV_CHECK_PRESENCE(struct lysc_node_leaf *, !(target->flags & LYS_SET_DFLT), dflt, "replacing",
+                                   "default", d->dflt);
+
+                /* remove the default specification */
+                leaf->dflt->realtype->plugin->free(ctx->ctx, leaf->dflt);
+                lysc_type_free(ctx->ctx, leaf->dflt->realtype);
+                free(leaf->dflt);
+                leaf->dflt = NULL;
+            } else {
+                /* local deviation */
+                DEV_CHECK_PRESENCE(struct lysc_node_leaf *, !(target->flags & LYS_SET_DFLT), name, "replacing",
+                                   "default", d->dflt);
+                assert(!leaf->dflt);
+            }
+
+            /* store the new default value */
+            LY_CHECK_RET(lysc_incomplete_leaf_dflt_add(ctx, leaf, d->dflt, ctx->mod_def));
             break;
         case LYS_CHOICE:
             DEV_CHECK_PRESENCE(struct lysc_node_choice *, 0, dflt, "replacing", "default", d->dflt);
@@ -6333,17 +6300,12 @@
 static LY_ERR
 lys_apply_deviation(struct lysc_ctx *ctx, struct lysc_deviation *dev)
 {
-    LY_ERR ret = LY_EVALID, rc;
+    LY_ERR ret = LY_EVALID;
     struct lysc_node *target = dev->target;
-    struct lysc_node_leaf *leaf = (struct lysc_node_leaf *)target;
-    struct lysc_node_leaflist *llist = (struct lysc_node_leaflist *)target;
-    struct ly_err_item *err = NULL;
     struct lysc_action *rpcs;
     struct lysc_notif *notifs;
     struct lysp_deviate *d;
     LY_ARRAY_COUNT_TYPE v, x;
-    int changed_type = 0;
-    const char *dflt = NULL;
     uint32_t min, max;
 
     lysc_update_path(ctx, NULL, dev->nodeid);
@@ -6406,13 +6368,13 @@
         d = dev->deviates[v];
         switch (d->mod) {
         case LYS_DEV_ADD:
-            LY_CHECK_GOTO(lys_apply_deviate_add(ctx, target, dev->flags, (struct lysp_deviate_add *)d, &dflt), cleanup);
+            LY_CHECK_GOTO(lys_apply_deviate_add(ctx, target, dev->flags, (struct lysp_deviate_add *)d), cleanup);
             break;
         case LYS_DEV_DELETE:
             LY_CHECK_GOTO(lys_apply_deviate_delete(ctx, target, dev->flags, (struct lysp_deviate_del *)d), cleanup);
             break;
         case LYS_DEV_REPLACE:
-            LY_CHECK_GOTO(lys_apply_deviate_replace(ctx, target, (struct lysp_deviate_rpl *)d, &dflt, &changed_type), cleanup);
+            LY_CHECK_GOTO(lys_apply_deviate_replace(ctx, target, (struct lysp_deviate_rpl *)d), cleanup);
             break;
         default:
             LOGINT(ctx->ctx);
@@ -6438,96 +6400,6 @@
         goto cleanup;
     }
 
-    if (dflt) {
-        /* parse added/changed default value after possible change of the type */
-        leaf->dflt_mod = ctx->mod_def;
-        leaf->dflt->realtype = leaf->type;
-        rc = leaf->type->plugin->store(ctx->ctx, leaf->type, dflt, strlen(dflt),
-                                        LY_TYPE_OPTS_INCOMPLETE_DATA | LY_TYPE_OPTS_SCHEMA | LY_TYPE_OPTS_STORE,
-                                        LY_PREF_SCHEMA, leaf->dflt_mod, target, NULL, leaf->dflt, NULL, &err);
-        leaf->dflt->realtype->refcount++;
-        if (err) {
-            ly_err_print(err);
-            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
-                    "Invalid deviation setting \"default\" property \"%s\" which does not fit the type (%s).", dflt, err->msg);
-            ly_err_free(err);
-        }
-        if (rc == LY_EINCOMPLETE) {
-            /* postpone default compilation when the tree is complete */
-            LY_CHECK_GOTO(lysc_incomplete_dflts_add(ctx, target, leaf->dflt, leaf->dflt_mod), cleanup);
-
-            /* but in general result is so far ok */
-            rc = LY_SUCCESS;
-        }
-        LY_CHECK_GOTO(rc, cleanup);
-    } else if (changed_type) {
-        /* the leaf/leaf-list's type has changed, but there is still a default value for the previous type */
-        int dynamic;
-        if (target->nodetype == LYS_LEAF) {
-            dflt = leaf->dflt->realtype->plugin->print(leaf->dflt, LY_PREF_SCHEMA, leaf->dflt_mod, &dynamic);
-
-            /* update the list of incomplete default values if needed */
-            lysc_incomplete_dflts_remove(ctx, leaf->dflt);
-
-            /* remove the previous default */
-            leaf->dflt->realtype->plugin->free(ctx->ctx, leaf->dflt);
-            lysc_type_free(ctx->ctx, leaf->dflt->realtype);
-            leaf->dflt->realtype = leaf->type;
-            rc = leaf->type->plugin->store(ctx->ctx, leaf->type, dflt, strlen(dflt),
-                                            LY_TYPE_OPTS_INCOMPLETE_DATA | LY_TYPE_OPTS_SCHEMA | LY_TYPE_OPTS_STORE,
-                                            LY_PREF_SCHEMA, leaf->dflt_mod, target, NULL, leaf->dflt, NULL, &err);
-            leaf->dflt->realtype->refcount++;
-            if (err) {
-                ly_err_print(err);
-                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
-                        "Invalid deviation replacing leaf's type - the leaf's default value \"%s\" does not match the type (%s).", dflt, err->msg);
-                ly_err_free(err);
-            }
-            if (dynamic) {
-                free((void*)dflt);
-            }
-            dflt = NULL;
-            if (rc == LY_EINCOMPLETE) {
-                /* postpone default compilation when the tree is complete */
-                LY_CHECK_GOTO(lysc_incomplete_dflts_add(ctx, target, leaf->dflt, leaf->dflt_mod), cleanup);
-
-                /* but in general result is so far ok */
-                rc = LY_SUCCESS;
-            }
-            LY_CHECK_GOTO(rc, cleanup);
-        } else { /* LYS_LEAFLIST */
-            LY_ARRAY_FOR(llist->dflts, x) {
-                dflt = llist->dflts[x]->realtype->plugin->print(llist->dflts[x], LY_PREF_SCHEMA, llist->dflts_mods[x], &dynamic);
-                llist->dflts[x]->realtype->plugin->free(ctx->ctx, llist->dflts[x]);
-                lysc_type_free(ctx->ctx, llist->dflts[x]->realtype);
-                llist->dflts[x]->realtype = llist->type;
-                rc = llist->type->plugin->store(ctx->ctx, llist->type, dflt, strlen(dflt),
-                                                LY_TYPE_OPTS_INCOMPLETE_DATA | LY_TYPE_OPTS_SCHEMA | LY_TYPE_OPTS_STORE,
-                                                LY_PREF_SCHEMA, llist->dflts_mods[x], target, NULL, llist->dflts[x], NULL, &err);
-                llist->dflts[x]->realtype->refcount++;
-                if (err) {
-                    ly_err_print(err);
-                    LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
-                               "Invalid deviation replacing leaf-list's type - the leaf-list's default value \"%s\" does not match the type (%s).",
-                            dflt, err->msg);
-                    ly_err_free(err);
-                }
-                if (dynamic) {
-                    free((void*)dflt);
-                }
-                dflt = NULL;
-                if (rc == LY_EINCOMPLETE) {
-                    /* postpone default compilation when the tree is complete */
-                    LY_CHECK_GOTO(lysc_incomplete_dflts_add(ctx, target, llist->dflts[x], llist->dflts_mods[x]), cleanup);
-
-                    /* but in general result is so far ok */
-                    rc = LY_SUCCESS;
-                }
-                LY_CHECK_GOTO(rc, cleanup);
-            }
-        }
-    }
-
     /* check mandatory - default compatibility */
     if ((target->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && (target->flags & LYS_SET_DFLT)
             && (target->flags & LYS_MAND_TRUE)) {
@@ -6811,7 +6683,7 @@
                     LY_CHECK_ERR_GOTO(r = lysp_stmt_parse(ctx, stmt, stmt->kw, &parsed, NULL), ret = r, cleanup);
                     LY_CHECK_ERR_GOTO(r = lys_compile_type(ctx, ext->parent_type == LYEXT_PAR_NODE ? ((struct lysc_node*)ext->parent)->sp : NULL,
                                       flags ? *flags : 0, ctx->mod_def->parsed, ext->name, parsed, (struct lysc_type**)compiled,
-                                      units && !*units ? units : NULL), lysp_type_free(ctx->ctx, parsed); free(parsed); ret = r, cleanup);
+                                      units && !*units ? units : NULL, NULL, NULL), lysp_type_free(ctx->ctx, parsed); free(parsed); ret = r, cleanup);
                     lysp_type_free(ctx->ctx, parsed);
                     free(parsed);
                     break;
@@ -7196,6 +7068,122 @@
 }
 
 static LY_ERR
+lys_compile_unres_dflt(struct lysc_ctx *ctx, struct lysc_node *node, struct lysc_type *type, const char *dflt,
+                       const struct lys_module *dflt_mod, struct lyd_value *storage)
+{
+    LY_ERR ret;
+    struct ly_err_item *err = NULL;
+
+    ret = type->plugin->store(ctx->ctx, type, dflt, strlen(dflt), LY_TYPE_OPTS_SCHEMA,
+                              LY_PREF_SCHEMA, (void *)dflt_mod, node, NULL, storage, &err);
+    if (err) {
+        ly_err_print(err);
+        ctx->path[0] = '\0';
+        lysc_path(node, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
+        LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+               "Invalid default - value does not fit the type (%s).", err->msg);
+        ly_err_free(err);
+    }
+    if (!ret) {
+        ++storage->realtype->refcount;
+        return LY_SUCCESS;
+    }
+    return ret;
+}
+
+static LY_ERR
+lys_compile_unres_leaf_dlft(struct lysc_ctx *ctx, struct lysc_node_leaf *leaf, const char *dflt,
+                            const struct lys_module *dflt_mod)
+{
+    LY_ERR ret;
+
+    assert(!leaf->dflt);
+
+    if (leaf->flags & (LYS_MAND_TRUE | LYS_KEY)) {
+        /* ignore default values for keys and mandatory leaves */
+        return LY_SUCCESS;
+    }
+
+    /* allocate the default value */
+    leaf->dflt = calloc(1, sizeof *leaf->dflt);
+    LY_CHECK_ERR_RET(!leaf->dflt, LOGMEM(ctx->ctx), LY_EMEM);
+
+    /* store the default value */
+    ret = lys_compile_unres_dflt(ctx, (struct lysc_node *)leaf, leaf->type, dflt, dflt_mod, leaf->dflt);
+    if (ret) {
+        free(leaf->dflt);
+        leaf->dflt = NULL;
+    }
+
+    return ret;
+}
+
+static LY_ERR
+lys_compile_unres_llist_dflts(struct lysc_ctx *ctx, struct lysc_node_leaflist *llist, const char *dflt, const char **dflts,
+                              const struct lys_module *dflt_mod)
+{
+    LY_ERR ret;
+    LY_ARRAY_COUNT_TYPE orig_count, u, v;
+
+    assert(dflt || dflts);
+
+    if (llist->dflts) {
+        /* there were already some defaults and we are adding new by deviations */
+        assert(dflts);
+        orig_count = LY_ARRAY_COUNT(llist->dflts);
+    } else {
+        orig_count = 0;
+    }
+
+    /* allocate new items */
+    if (dflts) {
+        LY_ARRAY_CREATE_RET(ctx->ctx, llist->dflts, orig_count + LY_ARRAY_COUNT(dflts), LY_EMEM);
+    } else {
+        LY_ARRAY_CREATE_RET(ctx->ctx, llist->dflts, orig_count + 1, LY_EMEM);
+    }
+
+    /* fill each new default value */
+    if (dflts) {
+        LY_ARRAY_FOR(dflts, u) {
+            llist->dflts[orig_count + u] = calloc(1, sizeof **llist->dflts);
+            ret = lys_compile_unres_dflt(ctx, (struct lysc_node *)llist, llist->type, dflts[u], dflt_mod,
+                                         llist->dflts[orig_count + u]);
+            LY_CHECK_ERR_RET(ret, free(llist->dflts[orig_count + u]), ret);
+            LY_ARRAY_INCREMENT(llist->dflts);
+        }
+    } else {
+        llist->dflts[orig_count] = calloc(1, sizeof **llist->dflts);
+        ret = lys_compile_unres_dflt(ctx, (struct lysc_node *)llist, llist->type, dflt, dflt_mod, llist->dflts[orig_count]);
+        LY_CHECK_ERR_RET(ret, free(llist->dflts[orig_count]), ret);
+        LY_ARRAY_INCREMENT(llist->dflts);
+    }
+
+    /* check default value uniqueness */
+    if (llist->flags & LYS_CONFIG_W) {
+        /* configuration data values must be unique - so check the default values */
+        for (u = orig_count; u < LY_ARRAY_COUNT(llist->dflts); ++u) {
+            for (v = 0; v < u; ++v) {
+                if (!llist->dflts[u]->realtype->plugin->compare(llist->dflts[u], llist->dflts[v])) {
+                    int dynamic = 0;
+                    const char *val = llist->type->plugin->print(llist->dflts[u], LY_PREF_SCHEMA, (void *)dflt_mod, &dynamic);
+
+                    lysc_update_path(ctx, llist->parent, llist->name);
+                    LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+                        "Configuration leaf-list has multiple defaults of the same value \"%s\".", val);
+                    lysc_update_path(ctx, NULL, NULL);
+                    if (dynamic) {
+                        free((char *)val);
+                    }
+                    return LY_EVALID;
+                }
+            }
+        }
+    }
+
+    return LY_SUCCESS;
+}
+
+static LY_ERR
 lys_compile_unres(struct lysc_ctx *ctx)
 {
     struct lysc_node *node;
@@ -7249,21 +7237,12 @@
 
     /* finish incomplete default values compilation */
     for (i = 0; i < ctx->dflts.count; ++i) {
-        struct ly_err_item *err = NULL;
         struct lysc_incomplete_dflt *r = ctx->dflts.objs[i];
-        LY_ERR ret;
-        ret = r->dflt->realtype->plugin->store(ctx->ctx, r->dflt->realtype, r->dflt->original, strlen(r->dflt->original),
-                                               LY_TYPE_OPTS_SCHEMA | LY_TYPE_OPTS_STORE | LY_TYPE_OPTS_SECOND_CALL,
-                                               LY_PREF_SCHEMA, r->dflt_mod, r->context_node, NULL, r->dflt, NULL, &err);
-        if (err) {
-            ly_err_print(err);
-            ctx->path[0] = '\0';
-            lysc_path(r->context_node, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
-            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
-                   "Invalid default - value does not fit the type (%s).", err->msg);
-            ly_err_free(err);
+        if (r->leaf->nodetype == LYS_LEAF) {
+            LY_CHECK_RET(lys_compile_unres_leaf_dlft(ctx, r->leaf, r->dflt, r->dflt_mod));
+        } else {
+            LY_CHECK_RET(lys_compile_unres_llist_dflts(ctx, r->llist, r->dflt, r->dflts, r->dflt_mod));
         }
-        LY_CHECK_RET(ret);
     }
 
     return LY_SUCCESS;
diff --git a/src/tree_schema_free.c b/src/tree_schema_free.c
index 232d66f..22843af 100644
--- a/src/tree_schema_free.c
+++ b/src/tree_schema_free.c
@@ -597,13 +597,6 @@
     if (--type->refcount) {
         return;
     }
-    FREE_ARRAY(ctx, type->exts, lysc_ext_instance_free);
-    if (type->dflt) {
-        type->plugin->free(ctx, type->dflt);
-        lysc_type_free(ctx, type->dflt->realtype);
-        free(type->dflt);
-        type->dflt = NULL;
-    }
 
     switch(type->basetype) {
     case LY_TYPE_BINARY:
@@ -648,6 +641,8 @@
         /* nothing to do */
         break;
     }
+
+    FREE_ARRAY(ctx, type->exts, lysc_ext_instance_free);
     free(type);
 }
 
@@ -736,7 +731,6 @@
         free(node->dflts[u]);
     }
     LY_ARRAY_FREE(node->dflts);
-    LY_ARRAY_FREE(node->dflts_mods);
 }
 
 static void
diff --git a/src/tree_schema_internal.h b/src/tree_schema_internal.h
index 8e132b9..9ed3b3f 100644
--- a/src/tree_schema_internal.h
+++ b/src/tree_schema_internal.h
@@ -160,9 +160,13 @@
 void yin_parser_ctx_free(struct lys_yin_parser_ctx *ctx);
 
 struct lysc_incomplete_dflt {
-    struct lyd_value *dflt;
+    union {
+        struct lysc_node_leaf *leaf;
+        struct lysc_node_leaflist *llist;
+    };
+    const char *dflt;
+    const char **dflts;
     struct lys_module *dflt_mod;
-    struct lysc_node *context_node;
 };
 
 /**
diff --git a/src/validation.c b/src/validation.c
index f278cc6..8377fc1 100644
--- a/src/validation.c
+++ b/src/validation.c
@@ -172,7 +172,7 @@
             struct lyd_node_term *node = (struct lyd_node_term *)node_types->objs[i];
 
             /* validate and store the value of the node */
-            ret = lyd_value_parse(node, node->value.original, strlen(node->value.original), 0, 1, 0, format,
+            ret = lyd_value_parse(node, node->value.canonical, strlen(node->value.canonical), 0, 1, 0, format,
                                   prefix_data, *tree);
             LY_CHECK_RET(ret);
 
@@ -190,8 +190,8 @@
             struct lyd_meta *meta = (struct lyd_meta *)meta_types->objs[i];
 
             /* validate and store the value of the metadata */
-            ret = lyd_value_parse_meta(meta->parent->schema->module->ctx, meta, meta->value.original,
-                                       strlen(meta->value.original), 0, 1, 0, format, prefix_data, NULL, *tree);
+            ret = lyd_value_parse_meta(meta->parent->schema->module->ctx, meta, meta->value.canonical,
+                                       strlen(meta->value.canonical), 0, 1, 0, format, prefix_data, NULL, *tree);
             LY_CHECK_RET(ret);
 
             /* remove this attr from the set */
diff --git a/src/xpath.c b/src/xpath.c
index fe0b70d..2e1a79e 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -165,7 +165,6 @@
 {
     uint32_t i;
     char *str;
-    int dynamic;
     struct lyxp_set_node *item;
     struct lyxp_set_scnode *sitem;
 
@@ -193,18 +192,10 @@
                 if ((item->node->schema->nodetype == LYS_LIST)
                         && (((struct lyd_node_inner *)item->node)->child->schema->nodetype == LYS_LEAF)) {
                     LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ELEM %s (1st child val: %s)", i + 1, item->pos,
-                           item->node->schema->name,
-                           (str = (char *)lyd_value2str((struct lyd_node_term *)lyd_node_children(item->node, 0), &dynamic)));
-                    if (dynamic) {
-                        free(str);
-                    }
+                           item->node->schema->name, LYD_CANONICAL(lyd_node_children(item->node, 0)));
                 } else if (((struct lyd_node_inner *)item->node)->schema->nodetype == LYS_LEAFLIST) {
                     LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ELEM %s (val: %s)", i + 1, item->pos,
-                           item->node->schema->name,
-                           (str = (char *)lyd_value2str((struct lyd_node_term *)item->node, &dynamic)));
-                    if (dynamic) {
-                        free(str);
-                    }
+                           item->node->schema->name, LYD_CANONICAL(item->node));
                 } else {
                     LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ELEM %s", i + 1, item->pos, item->node->schema->name);
                 }
@@ -214,11 +205,7 @@
                     LOGDBG(LY_LDGXPATH, "\t%d (pos %u): TEXT <%s>", i + 1, item->pos,
                            item->node->schema->nodetype == LYS_ANYXML ? "anyxml" : "anydata");
                 } else {
-                    LOGDBG(LY_LDGXPATH, "\t%d (pos %u): TEXT %s", i + 1, item->pos,
-                           (str = (char *)lyd_value2str((struct lyd_node_term *)item->node, &dynamic)));
-                    if (dynamic) {
-                        free(str);
-                    }
+                    LOGDBG(LY_LDGXPATH, "\t%d (pos %u): TEXT %s", i + 1, item->pos, LYD_CANONICAL(item->node));
                 }
                 break;
             case LYXP_NODE_META:
@@ -336,7 +323,6 @@
 {
     char *buf, *line, *ptr = NULL;
     const char *value_str;
-    int dynamic;
     const struct lyd_node *child;
     struct lyd_node *tree;
     struct lyd_node_any *any;
@@ -374,16 +360,10 @@
 
     case LYS_LEAF:
     case LYS_LEAFLIST:
-        value_str = lyd_value2str(((struct lyd_node_term *)node), &dynamic);
+        value_str = LYD_CANONICAL(node);
 
         /* print indent */
-        rc = cast_string_realloc(LYD_NODE_CTX(node), indent * 2 + strlen(value_str) + 1, str, used, size);
-        if (rc != LY_SUCCESS) {
-            if (dynamic) {
-                free((char *)value_str);
-            }
-            return rc;
-        }
+        LY_CHECK_RET(cast_string_realloc(LYD_NODE_CTX(node), indent * 2 + strlen(value_str) + 1, str, used, size));
         memset(*str + (*used - 1), ' ', indent * 2);
         *used += indent * 2;
 
@@ -395,9 +375,6 @@
             sprintf(*str + (*used - 1), "%s\n", value_str);
             *used += strlen(value_str) + 1;
         }
-        if (dynamic) {
-            free((char *)value_str);
-        }
 
         break;
 
@@ -522,8 +499,6 @@
 static LY_ERR
 cast_node_set_to_string(struct lyxp_set *set, char **str)
 {
-    int dynamic;
-
     switch (set->val.nodes[0].type) {
     case LYXP_NODE_NONE:
         /* invalid */
@@ -535,12 +510,9 @@
     case LYXP_NODE_TEXT:
         return cast_string_elem(set->val.nodes[0].node, 0, set->root_type, str);
     case LYXP_NODE_META:
-        *str = (char *)lyd_meta2str(set->val.meta[0].meta, &dynamic);
-        if (!dynamic) {
-            *str = strdup(*str);
-            if (!*str) {
-                LOGMEM_RET(set->ctx);
-            }
+        *str = strdup(set->val.meta[0].meta->value.canonical);
+        if (!*str) {
+            LOGMEM_RET(set->ctx);
         }
         return LY_SUCCESS;
     }
@@ -1565,9 +1537,8 @@
     }
 
     /* ignore errors, the value may not satisfy schema constraints */
-    rc = type->plugin->store(src->ctx, type, str, strlen(str),
-                             LY_TYPE_OPTS_STORE | LY_TYPE_OPTS_INCOMPLETE_DATA | LY_TYPE_OPTS_DYNAMIC, LY_PREF_JSON,
-                             NULL, NULL, NULL, &val, NULL, &err);
+    rc = type->plugin->store(src->ctx, type, str, strlen(str), LY_TYPE_OPTS_INCOMPLETE_DATA | LY_TYPE_OPTS_DYNAMIC,
+                             LY_PREF_JSON, NULL, NULL, NULL, &val, &err);
     ly_err_free(err);
     if (rc) {
         /* invalid value */
@@ -3307,6 +3278,7 @@
     struct lysc_node *scnode;
     struct lysc_type *type;
     char *value;
+    struct lyd_value storage;
     LY_ERR rc;
     struct ly_err_item *err = NULL;
 
@@ -3334,7 +3306,7 @@
         type = ((struct lysc_node_leaf *)scnode)->type;
         if (type->basetype != LY_TYPE_IDENT) {
             rc = type->plugin->store(set->ctx, type, value, strlen(value), LY_TYPE_OPTS_SCHEMA, LY_PREF_SCHEMA,
-                                     (void *)set->local_mod, NULL, NULL, NULL, NULL, &err);
+                                     (void *)set->local_mod, NULL, NULL, &storage, &err);
 
             if (err) {
                 LOGWRN(set->ctx, "Invalid value \"%s\" which does not fit the type (%s).", value, err->msg);
@@ -3346,6 +3318,8 @@
                 LOGWRN(set->ctx, "Previous warning generated by XPath subexpression[%u] \"%.*s\".", exp->tok_pos[equal_exp],
                     (exp->tok_pos[last_equal_exp] - exp->tok_pos[equal_exp]) + exp->tok_len[last_equal_exp],
                     exp->expr + exp->tok_pos[equal_exp]);
+            } else {
+                type->plugin->free(set->ctx, &storage);
             }
         }
         free(value);
@@ -3677,8 +3651,6 @@
     struct ly_path *p;
     struct lyd_node *node;
     char *errmsg = NULL;
-    const char *val;
-    int dynamic;
     uint8_t oper;
     LY_ERR rc = LY_SUCCESS;
 
@@ -3732,11 +3704,8 @@
             } else {
                 assert(sleaf->type->basetype == LY_TYPE_INST);
                 if (ly_path_eval(leaf->value.target, set->tree, &node)) {
-                    val = lyd_value2str(leaf, &dynamic);
-                    LOGERR(set->ctx, LY_EVALID, "Invalid instance-identifier \"%s\" value - required instance not found.", val);
-                    if (dynamic) {
-                        free((char *)val);
-                    }
+                    LOGERR(set->ctx, LY_EVALID, "Invalid instance-identifier \"%s\" value - required instance not found.",
+                           LYD_CANONICAL(leaf));
                     return LY_EVALID;
                 }
             }
@@ -3810,8 +3779,8 @@
 
             /* store args[1] as ident */
             rc = val->realtype->plugin->store(set->ctx, val->realtype, args[1]->val.str, strlen(args[1]->val.str),
-                                              LY_TYPE_OPTS_STORE, set->format, (void *)set->local_mod,
-                                              (struct lyd_node *)leaf, set->tree, &data, NULL, &err);
+                                              0, set->format, (void *)set->local_mod,
+                                              (struct lyd_node *)leaf, set->tree, &data, &err);
         } else {
             meta = args[0]->val.meta[i].meta;
             val = &meta->value;
@@ -3822,8 +3791,8 @@
 
             /* store args[1] as ident */
             rc = val->realtype->plugin->store(set->ctx, val->realtype, args[1]->val.str, strlen(args[1]->val.str),
-                                              LY_TYPE_OPTS_STORE, set->format, (void *)meta->annotation->module,
-                                              meta->parent, set->tree, &data, NULL, &err);
+                                              0, set->format, (void *)meta->annotation->module,
+                                              meta->parent, set->tree, &data, &err);
         }
 
         if (err) {
@@ -4000,7 +3969,7 @@
     struct lysc_node_leaf *sleaf;
     struct lyd_meta *meta = NULL;
     const char *val;
-    int i, dynamic;
+    int i;
     LY_ERR rc = LY_SUCCESS;
 
     if (options & LYXP_SCNODE_ALL) {
@@ -4058,7 +4027,7 @@
     if (!meta) {
         set_fill_boolean(set, 0);
     } else {
-        val = lyd_meta2str(meta, &dynamic);
+        val = meta->value.canonical;
         for (i = 0; args[0]->val.str[i]; ++i) {
             if (tolower(args[0]->val.str[i]) != tolower(val[i])) {
                 set_fill_boolean(set, 0);
@@ -4072,9 +4041,6 @@
                 set_fill_boolean(set, 0);
             }
         }
-        if (dynamic) {
-            free((char *)val);
-        }
     }
 
     return LY_SUCCESS;
diff --git a/tests/utests/data/test_new.c b/tests/utests/data/test_new.c
index 50a7740..cfb7a6a 100644
--- a/tests/utests/data/test_new.c
+++ b/tests/utests/data/test_new.c
@@ -218,7 +218,6 @@
 
     LY_ERR ret;
     struct lyd_node *root, *node, *parent;
-    int dynamic;
 
     /* create 2 nodes */
     ret = lyd_new_path2(NULL, ctx, "/a:c/x[.='val']", "vvv", 0, 0, &root, &node);
@@ -227,24 +226,21 @@
     assert_string_equal(root->schema->name, "c");
     assert_non_null(node);
     assert_string_equal(node->schema->name, "x");
-    assert_string_equal("val", lyd_value2str((struct lyd_node_term *)node, &dynamic));
-    assert_int_equal(dynamic, 0);
+    assert_string_equal("val", LYD_CANONICAL(node));
 
     /* append another */
     ret = lyd_new_path2(root, NULL, "/a:c/x", "val2", 0, 0, &parent, &node);
     assert_int_equal(ret, LY_SUCCESS);
     assert_ptr_equal(parent, node);
     assert_string_equal(node->schema->name, "x");
-    assert_string_equal("val2", lyd_value2str((struct lyd_node_term *)node, &dynamic));
-    assert_int_equal(dynamic, 0);
+    assert_string_equal("val2", LYD_CANONICAL(node));
 
     /* and a last one */
     ret = lyd_new_path2(root, NULL, "x", "val3", 0, 0, &parent, &node);
     assert_int_equal(ret, LY_SUCCESS);
     assert_ptr_equal(parent, node);
     assert_string_equal(node->schema->name, "x");
-    assert_string_equal("val3", lyd_value2str((struct lyd_node_term *)node, &dynamic));
-    assert_int_equal(dynamic, 0);
+    assert_string_equal("val3", LYD_CANONICAL(node));
 
     lyd_free_tree(root);
 
@@ -276,8 +272,7 @@
     assert_int_equal(ret, LY_SUCCESS);
     assert_non_null(root);
     assert_string_equal(node->schema->name, "x");
-    assert_string_equal("val", lyd_value2str((struct lyd_node_term *)node, &dynamic));
-    assert_int_equal(dynamic, 0);
+    assert_string_equal("val", LYD_CANONICAL(node));
 
     ret = lyd_new_path2(root, NULL, "/a:l2[1]/c/x", "val", 0, 0, NULL, &node);
     assert_int_equal(ret, LY_EEXIST);
@@ -290,8 +285,7 @@
     assert_int_equal(ret, LY_SUCCESS);
     assert_non_null(node);
     assert_string_equal(node->schema->name, "x");
-    assert_string_equal("val2", lyd_value2str((struct lyd_node_term *)node, &dynamic));
-    assert_int_equal(dynamic, 0);
+    assert_string_equal("val2", LYD_CANONICAL(node));
 
     lyd_free_tree(root);
 
diff --git a/tests/utests/data/test_parser_json.c b/tests/utests/data/test_parser_json.c
index 90c7431..14370d8 100644
--- a/tests/utests/data/test_parser_json.c
+++ b/tests/utests/data/test_parser_json.c
@@ -138,12 +138,12 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("foo", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("foo value", leaf->value.original);
+    assert_string_equal("foo value", leaf->value.canonical);
 
     assert_int_equal(LYS_LEAF, tree->next->next->schema->nodetype);
     assert_string_equal("foo2", tree->next->next->schema->name);
     leaf = (struct lyd_node_term*)tree->next->next;
-    assert_string_equal("default-val", leaf->value.original);
+    assert_string_equal("default-val", leaf->value.canonical);
     assert_true(leaf->flags & LYD_DEFAULT);
 
     lyd_print_tree(out, tree, LYD_JSON, 0);
@@ -158,7 +158,7 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("foo2", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("default-val", leaf->value.original);
+    assert_string_equal("default-val", leaf->value.canonical);
     assert_false(leaf->flags & LYD_DEFAULT);
 
     lyd_print_tree(out, tree, LYD_JSON, 0);
@@ -173,7 +173,7 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("foo2", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("default-val", leaf->value.original);
+    assert_string_equal("default-val", leaf->value.canonical);
     assert_true(leaf->flags & LYD_DEFAULT);
 
     /* TODO default values
@@ -192,13 +192,13 @@
     assert_non_null(tree->meta);
     assert_string_equal("hint", tree->meta->name);
     assert_int_equal(LY_TYPE_INT8, tree->meta->value.realtype->basetype);
-    assert_string_equal("1", tree->meta->value.original);
+    assert_string_equal("1", tree->meta->value.canonical);
     assert_int_equal(1, tree->meta->value.int8);
     assert_ptr_equal(tree, tree->meta->parent);
     assert_non_null(tree->meta->next);
     assert_string_equal("hint", tree->meta->next->name);
     assert_int_equal(LY_TYPE_INT8, tree->meta->next->value.realtype->basetype);
-    assert_string_equal("2", tree->meta->next->value.original);
+    assert_string_equal("2", tree->meta->next->value.canonical);
     assert_int_equal(2, tree->meta->next->value.int8);
     assert_ptr_equal(tree, tree->meta->next->parent);
     assert_null(tree->meta->next->next);
@@ -242,13 +242,13 @@
     assert_int_equal(LYS_LEAFLIST, tree->schema->nodetype);
     assert_string_equal("ll1", tree->schema->name);
     ll = (struct lyd_node_term*)tree;
-    assert_string_equal("10", ll->value.original);
+    assert_string_equal("10", ll->value.canonical);
 
     assert_non_null(tree->next);
     assert_int_equal(LYS_LEAFLIST, tree->next->schema->nodetype);
     assert_string_equal("ll1", tree->next->schema->name);
     ll = (struct lyd_node_term*)tree->next;
-    assert_string_equal("11", ll->value.original);
+    assert_string_equal("11", ll->value.canonical);
 
     lyd_print_all(out, tree, LYD_JSON, 0);
     assert_string_equal(printed, data);
@@ -262,16 +262,16 @@
     assert_int_equal(LYS_LEAFLIST, tree->schema->nodetype);
     assert_string_equal("ll1", tree->schema->name);
     ll = (struct lyd_node_term*)tree;
-    assert_string_equal("10", ll->value.original);
+    assert_string_equal("10", ll->value.canonical);
     assert_null(ll->meta);
 
     assert_non_null(tree->next);
     assert_int_equal(LYS_LEAFLIST, tree->next->schema->nodetype);
     assert_string_equal("ll1", tree->next->schema->name);
     ll = (struct lyd_node_term*)tree->next;
-    assert_string_equal("11", ll->value.original);
+    assert_string_equal("11", ll->value.canonical);
     assert_non_null(ll->meta);
-    assert_string_equal("2", ll->meta->value.original);
+    assert_string_equal("2", ll->meta->value.canonical);
     assert_null(ll->meta->next);
 
     lyd_print_all(out, tree, LYD_JSON, 0);
@@ -286,17 +286,17 @@
     assert_int_equal(LYS_LEAFLIST, tree->schema->nodetype);
     assert_string_equal("ll1", tree->schema->name);
     ll = (struct lyd_node_term*)tree;
-    assert_string_equal("1", ll->value.original);
+    assert_string_equal("1", ll->value.canonical);
     assert_non_null(ll->meta);
     assert_string_equal("hint", ll->meta->name);
     assert_int_equal(LY_TYPE_INT8, ll->meta->value.realtype->basetype);
-    assert_string_equal("1", ll->meta->value.original);
+    assert_string_equal("1", ll->meta->value.canonical);
     assert_int_equal(1, ll->meta->value.int8);
     assert_ptr_equal(ll, ll->meta->parent);
     assert_non_null(ll->meta->next);
     assert_string_equal("hint", ll->meta->next->name);
     assert_int_equal(LY_TYPE_INT8, ll->meta->next->value.realtype->basetype);
-    assert_string_equal("10", ll->meta->next->value.original);
+    assert_string_equal("10", ll->meta->next->value.canonical);
     assert_int_equal(10, ll->meta->next->value.int8);
     assert_ptr_equal(ll, ll->meta->next->parent);
     assert_null(ll->meta->next->next);
@@ -305,18 +305,18 @@
     assert_int_equal(LYS_LEAFLIST, tree->next->schema->nodetype);
     assert_string_equal("ll1", tree->next->schema->name);
     ll = (struct lyd_node_term*)tree->next;
-    assert_string_equal("2", ll->value.original);
+    assert_string_equal("2", ll->value.canonical);
     assert_null(ll->meta);
 
     assert_non_null(tree->next->next);
     assert_int_equal(LYS_LEAFLIST, tree->next->next->schema->nodetype);
     assert_string_equal("ll1", tree->next->next->schema->name);
     ll = (struct lyd_node_term*)tree->next->next;
-    assert_string_equal("3", ll->value.original);
+    assert_string_equal("3", ll->value.canonical);
     assert_non_null(ll->meta);
     assert_string_equal("hint", ll->meta->name);
     assert_int_equal(LY_TYPE_INT8, ll->meta->value.realtype->basetype);
-    assert_string_equal("3", ll->meta->value.original);
+    assert_string_equal("3", ll->meta->value.canonical);
     assert_int_equal(3, ll->meta->value.int8);
     assert_ptr_equal(ll, ll->meta->parent);
     assert_null(ll->meta->next);
@@ -467,7 +467,7 @@
     assert_string_equal("cp", tree->schema->name);
     assert_non_null(tree->meta);
     assert_string_equal("hint", tree->meta->name);
-    assert_string_equal("1", tree->meta->value.original);
+    assert_string_equal("1", tree->meta->value.canonical);
     assert_ptr_equal(tree, tree->meta->parent);
     assert_null(tree->meta->next);
 
diff --git a/tests/utests/data/test_parser_xml.c b/tests/utests/data/test_parser_xml.c
index 077c8b4..3632a3c 100644
--- a/tests/utests/data/test_parser_xml.c
+++ b/tests/utests/data/test_parser_xml.c
@@ -132,12 +132,12 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("foo", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("foo value", leaf->value.original);
+    assert_string_equal("foo value", leaf->value.canonical);
 
     assert_int_equal(LYS_LEAF, tree->next->next->schema->nodetype);
     assert_string_equal("foo2", tree->next->next->schema->name);
     leaf = (struct lyd_node_term*)tree->next->next;
-    assert_string_equal("default-val", leaf->value.original);
+    assert_string_equal("default-val", leaf->value.canonical);
     assert_true(leaf->flags & LYD_DEFAULT);
 
     lyd_free_all(tree);
@@ -149,7 +149,7 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("foo2", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("default-val", leaf->value.original);
+    assert_string_equal("default-val", leaf->value.canonical);
     assert_false(leaf->flags & LYD_DEFAULT);
 
     lyd_free_all(tree);
@@ -161,7 +161,7 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("foo2", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("default-val", leaf->value.original);
+    assert_string_equal("default-val", leaf->value.canonical);
     assert_true(leaf->flags & LYD_DEFAULT);
 
     lyd_free_all(tree);
diff --git a/tests/utests/data/test_tree_data.c b/tests/utests/data/test_tree_data.c
index 38a7239..9bb7f10 100644
--- a/tests/utests/data/test_tree_data.c
+++ b/tests/utests/data/test_tree_data.c
@@ -277,8 +277,7 @@
     struct lyd_node *tree;
     struct lyxp_expr *exp;
     struct ly_path *path;
-    const char *path_str = "/a:l2[2]/c/d[3]", *val;
-    int dynamic;
+    const char *path_str = "/a:l2[2]/c/d[3]";
     const char *data =
         "<l2 xmlns=\"urn:tests:a\"><c>"
             "<d>a</d>"
@@ -300,12 +299,8 @@
     term = lyd_target(path, tree);
 
     assert_string_equal(term->schema->name, "d");
-    val = lyd_value2str(term, &dynamic);
-    assert_int_equal(dynamic, 0);
-    assert_string_equal(val, "b");
-    val = lyd_value2str((struct lyd_node_term *)term->prev, &dynamic);
-    assert_int_equal(dynamic, 0);
-    assert_string_equal(val, "b");
+    assert_string_equal(LYD_CANONICAL(term), "b");
+    assert_string_equal(LYD_CANONICAL(term->prev), "b");
 
     lyd_free_all(tree);
     ly_path_free(ctx, path);
diff --git a/tests/utests/data/test_types.c b/tests/utests/data/test_types.c
index f78f851..900c9b2 100644
--- a/tests/utests/data/test_types.c
+++ b/tests/utests/data/test_types.c
@@ -181,12 +181,12 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("int8", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("15", leaf->value.canonical_cache);
+    assert_string_equal("15", leaf->value.canonical);
     assert_int_equal(15, leaf->value.int8);
 
     value.realtype = leaf->value.realtype;
     assert_int_equal(LY_SUCCESS, value.realtype->plugin->duplicate(s->ctx, &leaf->value, &value));
-    assert_string_equal(leaf->value.canonical_cache, value.canonical_cache);
+    assert_string_equal(leaf->value.canonical, value.canonical);
     assert_int_equal(15, value.int8);
     value.realtype->plugin->free(s->ctx, &value);
     memset(&value, 0, sizeof value);
@@ -222,12 +222,12 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("uint8", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("150", leaf->value.canonical_cache);
+    assert_string_equal("150", leaf->value.canonical);
     assert_int_equal(150, leaf->value.uint8);
 
     value.realtype = leaf->value.realtype;
     assert_int_equal(LY_SUCCESS, value.realtype->plugin->duplicate(s->ctx, &leaf->value, &value));
-    assert_string_equal(leaf->value.canonical_cache, value.canonical_cache);
+    assert_string_equal(leaf->value.canonical, value.canonical);
     assert_int_equal(150, value.uint8);
     value.realtype->plugin->free(s->ctx, &value);
     memset(&value, 0, sizeof value);
@@ -263,12 +263,12 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("dec64", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("8.0", leaf->value.canonical_cache);
+    assert_string_equal("8.0", leaf->value.canonical);
     assert_int_equal(80, leaf->value.dec64);
 
     value.realtype = leaf->value.realtype;
     assert_int_equal(LY_SUCCESS, value.realtype->plugin->duplicate(s->ctx, &leaf->value, &value));
-    assert_string_equal(leaf->value.canonical_cache, value.canonical_cache);
+    assert_string_equal(leaf->value.canonical, value.canonical);
     assert_int_equal(80, value.dec64);
     value.realtype->plugin->free(s->ctx, &value);
     memset(&value, 0, sizeof value);
@@ -278,7 +278,7 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("dec64", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("8.0", leaf->value.canonical_cache);
+    assert_string_equal("8.0", leaf->value.canonical);
     assert_int_equal(80, leaf->value.dec64);
     lyd_free_all(tree);
 
@@ -286,7 +286,7 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("dec64-norestr", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("-9.223372036854775808", leaf->value.canonical_cache);
+    assert_string_equal("-9.223372036854775808", leaf->value.canonical);
     assert_int_equal(INT64_C(-9223372036854775807) - INT64_C(1), leaf->value.dec64);
     lyd_free_all(tree);
 
@@ -294,7 +294,7 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("dec64-norestr", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("9.223372036854775807", leaf->value.canonical_cache);
+    assert_string_equal("9.223372036854775807", leaf->value.canonical);
     assert_int_equal(INT64_C(9223372036854775807), leaf->value.dec64);
     lyd_free_all(tree);
 
@@ -328,7 +328,7 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("str", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("teststring", leaf->value.canonical_cache);
+    assert_string_equal("teststring", leaf->value.canonical);
     lyd_free_all(tree);
 
     /* multibyte characters (€ encodes as 3-byte UTF8 character, length restriction is 2-5) */
@@ -336,7 +336,7 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("str-utf8", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("€€", leaf->value.canonical_cache);
+    assert_string_equal("€€", leaf->value.canonical);
     lyd_free_all(tree);
     TEST_DATA("<str-utf8 xmlns=\"urn:tests:types\">€</str-utf8>", LY_EVALID, "Length \"1\" does not satisfy the length constraint. /types:str-utf8");
     TEST_DATA("<str-utf8 xmlns=\"urn:tests:types\">€€€€€€</str-utf8>", LY_EVALID, "Length \"6\" does not satisfy the length constraint. /types:str-utf8");
@@ -369,14 +369,14 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("bits", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("zero two", leaf->value.canonical_cache);
+    assert_string_equal("zero two", leaf->value.canonical);
     assert_int_equal(2, LY_ARRAY_COUNT(leaf->value.bits_items));
     assert_string_equal("zero", leaf->value.bits_items[0]->name);
     assert_string_equal("two", leaf->value.bits_items[1]->name);
 
     value.realtype = leaf->value.realtype;
     assert_int_equal(LY_SUCCESS, value.realtype->plugin->duplicate(s->ctx, &leaf->value, &value));
-    assert_string_equal(leaf->value.canonical_cache, value.canonical_cache);
+    assert_string_equal(leaf->value.canonical, value.canonical);
     assert_int_equal(2, LY_ARRAY_COUNT(value.bits_items));
     assert_string_equal("zero", value.bits_items[0]->name);
     assert_string_equal("two", value.bits_items[1]->name);
@@ -388,7 +388,7 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("bits", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("zero two", leaf->value.canonical_cache);
+    assert_string_equal("zero two", leaf->value.canonical);
     lyd_free_all(tree);
 
     /* disabled feature */
@@ -400,13 +400,13 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("bits", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("one", leaf->value.canonical_cache);
+    assert_string_equal("one", leaf->value.canonical);
     assert_int_equal(1, LY_ARRAY_COUNT(leaf->value.bits_items));
     assert_string_equal("one", leaf->value.bits_items[0]->name);
 
     value.realtype = leaf->value.realtype;
     assert_int_equal(LY_SUCCESS, value.realtype->plugin->duplicate(s->ctx, &leaf->value, &value));
-    assert_string_equal(leaf->value.canonical_cache, value.canonical_cache);
+    assert_string_equal(leaf->value.canonical, value.canonical);
     assert_int_equal(1, LY_ARRAY_COUNT(value.bits_items));
     assert_string_equal("one", value.bits_items[0]->name);
     value.realtype->plugin->free(s->ctx, &value);
@@ -438,12 +438,12 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("enums", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("white", leaf->value.canonical_cache);
+    assert_string_equal("white", leaf->value.canonical);
     assert_string_equal("white", leaf->value.enum_item->name);
 
     value.realtype = leaf->value.realtype;
     assert_int_equal(LY_SUCCESS, value.realtype->plugin->duplicate(s->ctx, &leaf->value, &value));
-    assert_string_equal(leaf->value.canonical_cache, value.canonical_cache);
+    assert_string_equal(leaf->value.canonical, value.canonical);
     assert_string_equal("white", value.enum_item->name);
     value.realtype->plugin->free(s->ctx, &value);
     lyd_free_all(tree);
@@ -458,7 +458,7 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("enums", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("yellow", leaf->value.canonical_cache);
+    assert_string_equal("yellow", leaf->value.canonical);
     lyd_free_all(tree);
 
     /* leading/trailing whitespaces are not valid */
@@ -488,16 +488,16 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("binary", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("aGVs\nbG8=", leaf->value.canonical_cache);
+    assert_string_equal("aGVs\nbG8=", leaf->value.canonical);
     assert_non_null(tree = tree->next);
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("binary-norestr", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("TQ==", leaf->value.canonical_cache);
+    assert_string_equal("TQ==", leaf->value.canonical);
 
     value.realtype = leaf->value.realtype;
     assert_int_equal(LY_SUCCESS, value.realtype->plugin->duplicate(s->ctx, &leaf->value, &value));
-    assert_string_equal(leaf->value.canonical_cache, value.canonical_cache);
+    assert_string_equal(leaf->value.canonical, value.canonical);
     value.realtype->plugin->free(s->ctx, &value);
     memset(&value, 0, sizeof value);
     lyd_free_all(tree);
@@ -507,19 +507,19 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("binary-norestr", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("", leaf->value.canonical_cache);
+    assert_string_equal("</binary-norestr>", leaf->value.canonical);
     lyd_free_all(tree);
     TEST_DATA("<binary-norestr xmlns=\"urn:tests:types\"></binary-norestr>", LY_SUCCESS, "");
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("binary-norestr", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("", leaf->value.canonical_cache);
+    assert_string_equal("", leaf->value.canonical);
     lyd_free_all(tree);
     TEST_DATA("<binary-norestr xmlns=\"urn:tests:types\"/>", LY_SUCCESS, "");
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("binary-norestr", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("", leaf->value.canonical_cache);
+    assert_string_equal("", leaf->value.canonical);
     lyd_free_all(tree);
 
     /* invalid base64 character */
@@ -559,7 +559,7 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("bool", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("true", leaf->value.canonical_cache);
+    assert_string_equal("true", leaf->value.canonical);
     assert_int_equal(1, leaf->value.boolean);
     lyd_free_all(tree);
 
@@ -567,7 +567,7 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("bool", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("false", leaf->value.canonical_cache);
+    assert_string_equal("false", leaf->value.canonical);
     assert_int_equal(0, leaf->value.boolean);
     lyd_free_all(tree);
 
@@ -575,7 +575,7 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("tbool", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("false", leaf->value.canonical_cache);
+    assert_string_equal("false", leaf->value.canonical);
     assert_int_equal(0, leaf->value.boolean);
     lyd_free_all(tree);
 
@@ -603,21 +603,21 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("empty", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("", leaf->value.canonical_cache);
+    assert_string_equal("", leaf->value.canonical);
     lyd_free_all(tree);
 
     TEST_DATA("<empty xmlns=\"urn:tests:types\"/>", LY_SUCCESS, "");
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("empty", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("", leaf->value.canonical_cache);
+    assert_string_equal("", leaf->value.canonical);
     lyd_free_all(tree);
 
     TEST_DATA("<tempty xmlns=\"urn:tests:types\"/>", LY_SUCCESS, "");
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("tempty", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("", leaf->value.canonical_cache);
+    assert_string_equal("", leaf->value.canonical);
     lyd_free_all(tree);
 
     /* invalid value */
@@ -658,13 +658,14 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("ident", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_null(leaf->value.canonical_cache);
+    assert_non_null(leaf->value.canonical);
+    assert_string_equal("types:gigabit-ethernet", leaf->value.canonical);
     assert_string_equal("gigabit-ethernet", leaf->value.ident->name);
     test_printed_value(&leaf->value, "t:gigabit-ethernet", LY_PREF_SCHEMA, s->mod_types);
 
     value.realtype = leaf->value.realtype;
     assert_int_equal(LY_SUCCESS, value.realtype->plugin->duplicate(s->ctx, &leaf->value, &value));
-    assert_null(value.canonical_cache);
+    assert_string_equal("types:gigabit-ethernet", value.canonical);
     assert_string_equal("gigabit-ethernet", value.ident->name);
     value.realtype->plugin->free(s->ctx, &value);
     lyd_free_all(tree);
@@ -673,7 +674,7 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("ident", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_null(leaf->value.canonical_cache);
+    assert_string_equal("defs:fast-ethernet", leaf->value.canonical);
     test_printed_value(&leaf->value, "d:fast-ethernet", LY_PREF_SCHEMA, s->mod_defs);
     lyd_free_all(tree);
 
@@ -721,7 +722,7 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("inst", tree->schema->name);
     leaf = (const struct lyd_node_term*)tree;
-    assert_null(leaf->value.canonical_cache);
+    assert_string_equal("/types:cont/leaftarget", leaf->value.canonical);
     assert_int_equal(2, LY_ARRAY_COUNT(leaf->value.target));
     assert_string_equal("cont", leaf->value.target[0].node->name);
     assert_null(leaf->value.target[0].predicates);
@@ -730,7 +731,7 @@
 
     value.realtype = leaf->value.realtype;
     assert_int_equal(LY_SUCCESS, value.realtype->plugin->duplicate(s->ctx, &leaf->value, &value));
-    assert_null(value.canonical_cache);
+    assert_string_equal("/types:cont/leaftarget", value.canonical);
     assert_true(LY_ARRAY_COUNT(leaf->value.target) == LY_ARRAY_COUNT(value.target));
     assert_true(leaf->value.target[0].node == value.target[0].node);
     assert_true(leaf->value.target[0].predicates == value.target[0].predicates); /* NULL */
@@ -745,7 +746,7 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("inst", tree->schema->name);
     leaf = (const struct lyd_node_term*)tree;
-    assert_null(leaf->value.canonical_cache);
+    assert_string_equal("/types:list[id='b']/id", leaf->value.canonical);
     lyd_free_all(tree);
 
     TEST_DATA("<leaflisttarget xmlns=\"urn:tests:types\">1</leaflisttarget><leaflisttarget xmlns=\"urn:tests:types\">2</leaflisttarget>"
@@ -754,7 +755,7 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("inst", tree->schema->name);
     leaf = (const struct lyd_node_term*)tree;
-    assert_null(leaf->value.canonical_cache);
+    assert_string_equal("/types:leaflisttarget[.='1']", leaf->value.canonical);
     lyd_free_all(tree);
 
     TEST_DATA("<list_inst xmlns=\"urn:tests:types\"><id xmlns:b=\"urn:tests:types\">/b:leaflisttarget[.='a']</id><value>x</value></list_inst>"
@@ -765,7 +766,7 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("inst", tree->schema->name);
     leaf = (const struct lyd_node_term*)tree;
-    assert_null(leaf->value.canonical_cache);
+    assert_string_equal("/types:list_inst[id=\"/types:leaflisttarget[.='b']\"]/value", leaf->value.canonical);
     assert_int_equal(2, LY_ARRAY_COUNT(leaf->value.target));
     assert_string_equal("list_inst", leaf->value.target[0].node->name);
     assert_int_equal(1, LY_ARRAY_COUNT(leaf->value.target[0].predicates));
@@ -777,7 +778,7 @@
 
     value.realtype = leaf->value.realtype;
     assert_int_equal(LY_SUCCESS, value.realtype->plugin->duplicate(s->ctx, &leaf->value, &value));
-    assert_null(value.canonical_cache);
+    assert_string_equal("/types:list_inst[id=\"/types:leaflisttarget[.='b']\"]/value", value.canonical);
     assert_true(LY_ARRAY_COUNT(leaf->value.target) == LY_ARRAY_COUNT(value.target));
     assert_true(leaf->value.target[0].node == value.target[0].node);
     assert_true(LY_ARRAY_COUNT(leaf->value.target[0].predicates) == LY_ARRAY_COUNT(value.target[0].predicates));
@@ -792,7 +793,7 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("inst", tree->schema->name);
     leaf = (const struct lyd_node_term*)tree;
-    assert_null(leaf->value.canonical_cache);
+    assert_string_equal("/types:list[id='b']/value", leaf->value.canonical);
     lyd_free_all(tree);
 
     TEST_DATA("<list_inst xmlns=\"urn:tests:types\"><id xmlns:b=\"urn:tests:types\">/b:leaflisttarget[.='a']</id><value>x</value></list_inst>"
@@ -803,7 +804,7 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("inst", tree->schema->name);
     leaf = (const struct lyd_node_term*)tree;
-    assert_null(leaf->value.canonical_cache);
+    assert_string_equal("/types:list_inst[id=\"/types:leaflisttarget[.='a']\"]/value", leaf->value.canonical);
     lyd_free_all(tree);
 
     TEST_DATA("<list_ident xmlns=\"urn:tests:types\"><id xmlns:dfs=\"urn:tests:defs\">dfs:ethernet</id><value>x</value></list_ident>"
@@ -813,7 +814,8 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("inst", tree->schema->name);
     leaf = (const struct lyd_node_term*)tree;
-    assert_null(leaf->value.canonical_cache);
+    assert_non_null(leaf->value.canonical);
+    assert_string_equal("/types:list_ident[id='defs:fast-ethernet']/value", leaf->value.canonical);
     lyd_free_all(tree);
 
     TEST_DATA("<list2 xmlns=\"urn:tests:types\"><id>types:xxx</id><value>x</value></list2>"
@@ -823,7 +825,8 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("inst", tree->schema->name);
     leaf = (const struct lyd_node_term*)tree;
-    assert_null(leaf->value.canonical_cache);
+    assert_non_null(leaf->value.canonical);
+    assert_string_equal("/types:list2[id='a:xxx'][value='y']/value", leaf->value.canonical);
     lyd_free_all(tree);
 
     TEST_DATA("<list xmlns=\"urn:tests:types\"><id>types:xxx</id><value>x</value></list>"
@@ -833,7 +836,8 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("inst", tree->schema->name);
     leaf = (const struct lyd_node_term*)tree;
-    assert_null(leaf->value.canonical_cache);
+    assert_non_null(leaf->value.canonical);
+    assert_string_equal("/types:list[id='a:xxx']/value", leaf->value.canonical);
     lyd_free_all(tree);
 
     TEST_DATA("<list2 xmlns=\"urn:tests:types\"><id>a</id><value>a</value></list2>"
@@ -843,10 +847,11 @@
     leaf = (const struct lyd_node_term*)tree->prev->prev;
     assert_int_equal(LYS_LEAF, leaf->schema->nodetype);
     assert_string_equal("inst", leaf->schema->name);
-    assert_null(leaf->value.canonical_cache);
+    assert_non_null(leaf->value.canonical);
+    assert_string_equal("/types:list2[id='a'][value='b']/id", leaf->value.canonical);
     assert_non_null(leaf = lyd_target(leaf->value.target, tree));
-    assert_string_equal("a", leaf->value.canonical_cache);
-    assert_string_equal("b", ((struct lyd_node_term*)leaf->next)->value.canonical_cache);
+    assert_string_equal("a", leaf->value.canonical);
+    assert_string_equal("b", ((struct lyd_node_term*)leaf->next)->value.canonical);
     lyd_free_all(tree);
 
     /* invalid value */
@@ -864,10 +869,10 @@
     TEST_DATA("<inst xmlns=\"urn:tests:types\">/cont/leaftarget</inst>", LY_EVALID,
               "Invalid instance-identifier \"/cont/leaftarget\" value - syntax error. /types:inst");
 
-    /* instance-identifier is here in JSON format because it is already in internal representation without original prefixes */
+    /* instance-identifier is here in JSON format because it is already in internal representation without canonical prefixes */
     TEST_DATA( "<cont xmlns=\"urn:tests:types\"/><t:inst xmlns:t=\"urn:tests:types\">/t:cont/t:leaftarget</t:inst>", LY_EVALID, "Invalid instance-identifier \"/types:cont/leaftarget\" value - required instance not found. /types:inst");
 
-    /* instance-identifier is here in JSON format because it is already in internal representation without original prefixes */
+    /* instance-identifier is here in JSON format because it is already in internal representation without canonical prefixes */
     TEST_DATA( "<t:inst xmlns:t=\"urn:tests:types\">/t:cont/t:leaftarget</t:inst>", LY_EVALID, "Invalid instance-identifier \"/types:cont/leaftarget\" value - required instance not found. /types:inst");
 
     TEST_DATA("<leaflisttarget xmlns=\"urn:tests:types\">x</leaflisttarget><t:inst xmlns:t=\"urn:tests:types\">/t:leaflisttarget[1</t:inst>", LY_EVALID,
@@ -899,7 +904,7 @@
               "<t:inst xmlns:t=\"urn:tests:types\">/t:cont/t:listtarget[.='x']</t:inst>", LY_EVALID,
               "Invalid instance-identifier \"/t:cont/t:listtarget[.='x']\" value - semantic error. /types:inst");
 
-    /* instance-identifier is here in JSON format because it is already in internal representation without original prefixes */
+    /* instance-identifier is here in JSON format because it is already in internal representation without canonical prefixes */
     TEST_DATA("<cont xmlns=\"urn:tests:types\"><leaflisttarget>1</leaflisttarget></cont>"
               "<t:inst xmlns:t=\"urn:tests:types\">/t:cont/t:leaflisttarget[.='2']</t:inst>", LY_EVALID,
               "Invalid instance-identifier \"/types:cont/leaflisttarget[.='2']\" value - required instance not found. /types:inst");
@@ -910,7 +915,7 @@
               "<t:inst xmlns:t=\"urn:tests:types\">/t:cont/t:listtarget[t:id='x']</t:inst>", LY_EVALID,
               "Invalid instance-identifier \"/t:cont/t:listtarget[t:id='x']\" value - semantic error. /types:inst");
 
-    /* instance-identifier is here in JSON format because it is already in internal representation without original prefixes */
+    /* instance-identifier is here in JSON format because it is already in internal representation without canonical prefixes */
     TEST_DATA("<cont xmlns=\"urn:tests:types\"><listtarget><id>1</id><value>x</value></listtarget></cont>"
               "<t:inst xmlns:t=\"urn:tests:types\">/t:cont/t:listtarget[t:id='2']</t:inst>", LY_EVALID,
               "Invalid instance-identifier \"/types:cont/listtarget[id='2']\" value - required instance not found. /types:inst");
@@ -994,7 +999,7 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("lref", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("y", leaf->value.canonical_cache);
+    assert_string_equal("y", leaf->value.canonical);
     assert_int_equal(LY_TYPE_STRING, leaf->value.realtype->plugin->type);
     lyd_free_all(tree);
 
@@ -1005,7 +1010,7 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("lref2", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("y", leaf->value.canonical_cache);
+    assert_string_equal("y", leaf->value.canonical);
     lyd_free_all(tree);
 
     TEST_DATA("<str-norestr xmlns=\"urn:tests:types\">y</str-norestr>"
@@ -1014,7 +1019,7 @@
     leaf = (struct lyd_node_term*)(lyd_node_children(lyd_node_children(tree, 0)->next, 0)->prev);
     assert_int_equal(LYS_LEAF, leaf->schema->nodetype);
     assert_string_equal("lr1", leaf->schema->name);
-    assert_string_equal("y", leaf->value.canonical_cache);
+    assert_string_equal("y", leaf->value.canonical);
     lyd_free_all(tree);
 
     TEST_DATA("<str-norestr xmlns=\"urn:tests:types\">y</str-norestr>"
@@ -1024,7 +1029,7 @@
     leaf = (struct lyd_node_term*)(lyd_node_children(lyd_node_children(tree, 0)->prev, 0)->prev);
     assert_int_equal(LYS_LEAF, leaf->schema->nodetype);
     assert_string_equal("lr2", leaf->schema->name);
-    assert_string_equal("y", leaf->value.canonical_cache);
+    assert_string_equal("y", leaf->value.canonical);
     lyd_free_all(tree);
 
     TEST_DATA("<list xmlns=\"urn:tests:types\"><id>x</id><targets>a</targets><targets>b</targets></list>"
@@ -1035,7 +1040,7 @@
     leaf = (struct lyd_node_term*)(lyd_node_children(lyd_node_children(tree, 0)->prev, 0)->prev);
     assert_int_equal(LYS_LEAF, leaf->schema->nodetype);
     assert_string_equal("lr3", leaf->schema->name);
-    assert_string_equal("c", leaf->value.canonical_cache);
+    assert_string_equal("c", leaf->value.canonical);
     lyd_free_all(tree);
 
     /* invalid value */
@@ -1098,25 +1103,23 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("un1", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("12", leaf->value.original);
-    assert_null(leaf->value.canonical_cache);
+    assert_string_equal("12", leaf->value.canonical);
     assert_non_null(leaf->value.subvalue->prefix_data);
     assert_int_equal(((struct ly_set *)leaf->value.subvalue->prefix_data)->count, 1);
     assert_int_equal(LY_TYPE_UNION, leaf->value.realtype->basetype);
     assert_int_equal(LY_TYPE_INT8, leaf->value.subvalue->value->realtype->basetype);
-    assert_string_equal("12", leaf->value.subvalue->value->canonical_cache);
+    assert_string_equal("12", leaf->value.subvalue->value->canonical);
     assert_int_equal(12, leaf->value.subvalue->value->int8);
 
     test_printed_value(&leaf->value, "12", LY_PREF_SCHEMA, NULL);
 
     value.realtype = leaf->value.realtype;
     assert_int_equal(LY_SUCCESS, value.realtype->plugin->duplicate(s->ctx, &leaf->value, &value));
-    assert_string_equal("12", value.original);
-    assert_null(value.canonical_cache);
+    assert_string_equal("12", value.canonical);
     assert_non_null(value.subvalue->prefix_data);
     assert_int_equal(((struct ly_set *)leaf->value.subvalue->prefix_data)->count, 1);
     assert_int_equal(LY_TYPE_INT8, value.subvalue->value->realtype->basetype);
-    assert_string_equal("12", value.subvalue->value->canonical_cache);
+    assert_string_equal("12", value.subvalue->value->canonical);
     assert_int_equal(12, leaf->value.subvalue->value->int8);
     value.realtype->plugin->free(s->ctx, &value);
     lyd_free_all(tree);
@@ -1126,35 +1129,32 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("un1", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("2", leaf->value.original);
-    assert_null(leaf->value.canonical_cache);
+    assert_string_equal("2", leaf->value.canonical);
     assert_non_null(leaf->value.subvalue->prefix_data);
     assert_int_equal(((struct ly_set *)leaf->value.subvalue->prefix_data)->count, 1);
     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("2", leaf->value.subvalue->value->canonical_cache);
+    assert_string_equal("2", leaf->value.subvalue->value->canonical);
     lyd_free_all(tree);
 
     TEST_DATA("<un1 xmlns=\"urn:tests:types\" xmlns:x=\"urn:tests:defs\">x:fast-ethernet</un1>", LY_SUCCESS, "");
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("un1", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("x:fast-ethernet", leaf->value.original);
-    assert_null(leaf->value.canonical_cache);
+    assert_string_equal("defs:fast-ethernet", leaf->value.canonical);
     assert_non_null(leaf->value.subvalue->prefix_data);
     assert_int_equal(((struct ly_set *)leaf->value.subvalue->prefix_data)->count, 2);
     assert_int_equal(LY_TYPE_UNION, leaf->value.realtype->basetype);
     assert_int_equal(LY_TYPE_IDENT, leaf->value.subvalue->value->realtype->basetype);
-    assert_null(leaf->value.subvalue->value->canonical_cache); /* identityref does not have canonical form */
+    assert_string_equal("defs:fast-ethernet", leaf->value.subvalue->value->canonical);
 
     test_printed_value(&leaf->value, "d:fast-ethernet", LY_PREF_SCHEMA, s->mod_defs);
     test_printed_value(leaf->value.subvalue->value, "d:fast-ethernet", LY_PREF_SCHEMA, s->mod_defs);
 
     value.realtype = leaf->value.realtype;
     assert_int_equal(LY_SUCCESS, value.realtype->plugin->duplicate(s->ctx, &leaf->value, &value));
-    assert_string_equal("x:fast-ethernet", value.original);
-    assert_null(value.canonical_cache);
-    assert_null(value.subvalue->value->canonical_cache);
+    assert_string_equal("defs:fast-ethernet", value.canonical);
+    assert_string_equal("defs:fast-ethernet", value.subvalue->value->canonical);
     assert_non_null(value.subvalue->prefix_data);
     assert_int_equal(((struct ly_set *)leaf->value.subvalue->prefix_data)->count, 2);
     assert_int_equal(LY_TYPE_IDENT, value.subvalue->value->realtype->basetype);
@@ -1166,13 +1166,12 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("un1", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("d:superfast-ethernet", leaf->value.original);
-    assert_null(leaf->value.canonical_cache);
+    assert_string_equal("d:superfast-ethernet", leaf->value.canonical);
     assert_non_null(leaf->value.subvalue->prefix_data);
     assert_int_equal(((struct ly_set *)leaf->value.subvalue->prefix_data)->count, 2);
     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->canonical_cache);
+    assert_string_equal("d:superfast-ethernet", leaf->value.subvalue->value->canonical);
     lyd_free_all(tree);
 
     TEST_DATA("<leaflisttarget xmlns=\"urn:tests:types\">x</leaflisttarget><leaflisttarget xmlns=\"urn:tests:types\">y</leaflisttarget>"
@@ -1181,13 +1180,12 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("un1", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("/a:leaflisttarget[.='y']", leaf->value.original);
-    assert_null(leaf->value.canonical_cache);
+    assert_string_equal("/types:leaflisttarget[.='y']", leaf->value.canonical);
     assert_non_null(leaf->value.subvalue->prefix_data);
     assert_int_equal(((struct ly_set *)leaf->value.subvalue->prefix_data)->count, 2);
     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->canonical_cache); /* instance-identifier does not have canonical form */
+    assert_string_equal("/types:leaflisttarget[.='y']", leaf->value.subvalue->value->canonical);
     lyd_free_all(tree);
 
     TEST_DATA("<leaflisttarget xmlns=\"urn:tests:types\">x</leaflisttarget><leaflisttarget xmlns=\"urn:tests:types\">y</leaflisttarget>"
@@ -1196,13 +1194,12 @@
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("un1", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
-    assert_string_equal("/a:leaflisttarget[3]", leaf->value.original);
-    assert_null(leaf->value.canonical_cache);
+    assert_string_equal("/a:leaflisttarget[3]", leaf->value.canonical);
     assert_non_null(leaf->value.subvalue->prefix_data);
     assert_int_equal(((struct ly_set *)leaf->value.subvalue->prefix_data)->count, 2);
     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->canonical_cache);
+    assert_string_equal("/a:leaflisttarget[3]", leaf->value.subvalue->value->canonical);
     lyd_free_all(tree);
 
     TEST_DATA("<un1 xmlns=\"urn:tests:types\">123456789012345678901</un1>", LY_EVALID, "Invalid union value \"123456789012345678901\" - no matching subtype found. /types:un1");
diff --git a/tests/utests/schema/test_schema_stmts.c b/tests/utests/schema/test_schema_stmts.c
index d97fcc3..215ffd8 100644
--- a/tests/utests/schema/test_schema_stmts.c
+++ b/tests/utests/schema/test_schema_stmts.c
@@ -134,12 +134,12 @@
 
     /* default value from non-implemented module */
     TEST_SCHEMA_ERR(ctx, 0, 0, "ident2", "import base {prefix b;} leaf l {type identityref {base b:i1;} default b:i2;}",
-                    "Invalid leaf's default value \"b:i2\" which does not fit the type (Invalid identityref \"b:i2\" value"
+                    "Invalid default - value does not fit the type (Invalid identityref \"b:i2\" value"
                     " - identity found in non-implemented module \"base\".). /ident2:l");
 
     /* default value in typedef from non-implemented module */
     TEST_SCHEMA_ERR(ctx, 0, 0, "ident2", "import base {prefix b;} typedef t1 {type identityref {base b:i1;} default b:i2;}"
-                    "leaf l {type t1;}", "Invalid type's default value \"b:i2\" which does not fit the type (Invalid"
+                    "leaf l {type t1;}", "Invalid default - value does not fit the type (Invalid"
                     " identityref \"b:i2\" value - identity found in non-implemented module \"base\".). /ident2:l");
 
     /*
diff --git a/tests/utests/schema/test_tree_schema_compile.c b/tests/utests/schema/test_tree_schema_compile.c
index ba7d84a..e587bc2 100644
--- a/tests/utests/schema/test_tree_schema_compile.c
+++ b/tests/utests/schema/test_tree_schema_compile.c
@@ -285,7 +285,6 @@
     assert_non_null(l = (struct lysc_node_leaf*)mod->compiled->data);
     assert_string_equal("ref", l->name);
     assert_non_null(l->dflt);
-    assert_null(l->dflt->canonical_cache);
 
     /* invalid */
     assert_int_equal(LY_EVALID, lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa;leaf-list ll {type empty;}}",
@@ -293,7 +292,7 @@
     logbuf_assert("Leaf-list of type \"empty\" is allowed only in YANG 1.1 modules. /aa:ll");
 
     assert_int_equal(LY_EVALID, lys_parse_mem(ctx, "module bb {yang-version 1.1;namespace urn:bb;prefix bb;leaf-list ll {type empty; default x;}}", LYS_IN_YANG, NULL));
-    logbuf_assert("Invalid leaf-lists's default value \"x\" which does not fit the type (Invalid empty value \"x\".). /bb:ll");
+    logbuf_assert("Invalid default - value does not fit the type (Invalid empty value \"x\".). /bb:ll");
 
     assert_int_equal(LY_SUCCESS, lys_parse_mem(ctx, "module cc {yang-version 1.1;namespace urn:cc;prefix cc;"
                     "leaf-list ll {config false;type string; default one;default two;default one;}}", LYS_IN_YANG, &mod));
@@ -1918,7 +1917,7 @@
     /* invalid */
     assert_int_equal(LY_EVALID, lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa;"
                                         "leaf l {type empty; default x;}}", LYS_IN_YANG, NULL));
-    logbuf_assert("Invalid leaf's default value \"x\" which does not fit the type (Invalid empty value \"x\".). /aa:l");
+    logbuf_assert("Invalid default - value does not fit the type (Invalid empty value \"x\".). /aa:l");
 
     assert_int_equal(LY_EVALID, lys_parse_mem(ctx, "module bb {namespace urn:bb;prefix bb;typedef mytype {type empty; default x;}"
                                         "leaf l {type mytype;}}", LYS_IN_YANG, NULL));
@@ -2944,7 +2943,7 @@
     assert_int_equal(0, dynamic);
     assert_int_equal(1, llist->dflts[0]->uint8);
 
-    /* instance-identifiers with NULL canonical_cach are changed to string types with a canonical_cache value equal to the original value */
+    /* instance-identifiers with NULL canonical are changed to string types with a canonical value equal to the original value */
     assert_int_equal(LY_SUCCESS, lys_parse_mem(ctx, "module q {yang-version 1.1; namespace urn:q;prefix q; import e {prefix e;}"
                                         "leaf q {type instance-identifier; default \"/e:d2[.='a']\";}"
                                         "leaf-list ql {type instance-identifier; default \"/e:d[.='b']\"; default \"/e:d2[.='c']\";}}", LYS_IN_YANG, &mod));
@@ -2953,31 +2952,26 @@
                                   "deviation /q:ql { deviate replace {type string;}}}", LYS_IN_YANG, NULL));
     assert_non_null(leaf = (struct lysc_node_leaf*)mod->compiled->data);
     assert_int_equal(LY_TYPE_STRING, leaf->dflt->realtype->basetype);
-    assert_non_null(leaf->dflt->canonical_cache);
-    assert_string_equal("/e:d2[.='a']", leaf->dflt->canonical_cache);
+    assert_non_null(leaf->dflt->canonical);
+    assert_string_equal("/e:d2[.='a']", leaf->dflt->canonical);
     assert_non_null(llist = (struct lysc_node_leaflist*)leaf->next);
     assert_int_equal(2, LY_ARRAY_COUNT(llist->dflts));
-    assert_int_equal(2, LY_ARRAY_COUNT(llist->dflts_mods));
-    assert_ptr_equal(llist->dflts_mods[0], mod);
     assert_int_equal(LY_TYPE_STRING, llist->dflts[0]->realtype->basetype);
-    assert_string_equal("/e:d[.='b']", llist->dflts[0]->canonical_cache);
-    assert_ptr_equal(llist->dflts_mods[1], mod);
+    assert_string_equal("/e:d[.='b']", llist->dflts[0]->canonical);
     assert_int_equal(LY_TYPE_STRING, llist->dflts[0]->realtype->basetype);
-    assert_string_equal("/e:d2[.='c']", llist->dflts[1]->canonical_cache);
+    assert_string_equal("/e:d2[.='c']", llist->dflts[1]->canonical);
 
     assert_int_equal(LY_SUCCESS, lys_parse_mem(ctx, "module r {yang-version 1.1; namespace urn:r;prefix r;"
                                         "typedef mytype {type uint8; default 200;}"
                                         "leaf r {type mytype;} leaf-list lr {type mytype;}"
                                         "deviation /r:r {deviate replace {type string;}}"
                                         "deviation /r:lr {deviate replace {type string;}}}", LYS_IN_YANG, &mod));
-    assert_non_null(leaf = (struct lysc_node_leaf*)mod->compiled->data);
+    assert_non_null(leaf = (struct lysc_node_leaf *)mod->compiled->data);
     assert_string_equal("r", leaf->name);
     assert_null(leaf->dflt);
-    assert_null(leaf->dflt_mod);
     assert_non_null(llist = (struct lysc_node_leaflist* )leaf->next);
     assert_string_equal("lr", llist->name);
     assert_null(llist->dflts);
-    assert_null(llist->dflts_mods);
 
     assert_int_equal(LY_SUCCESS, lys_parse_mem(ctx, "module s {yang-version 1.1; namespace urn:s;prefix s;"
                                         "leaf s {type instance-identifier {require-instance true;} default /s:x;}"
@@ -3177,16 +3171,16 @@
 
     assert_int_equal(LY_EVALID, lys_parse_mem(ctx, "module oo1 {namespace urn:oo1;prefix oo1; leaf x {type uint16; default 300;}"
                                   "deviation /x {deviate replace {type uint8;}}}", LYS_IN_YANG, &mod));
-    logbuf_assert("Invalid deviation replacing leaf's type - the leaf's default value \"300\" does not match the type "
-                  "(Value \"300\" is out of uint8's min/max bounds.). /oo1:{deviation='/x'}");
+    logbuf_assert("Invalid default - value does not fit the type "
+                  "(Value \"300\" is out of uint8's min/max bounds.). /oo1:x");
     assert_int_equal(LY_EVALID, lys_parse_mem(ctx, "module oo2 {yang-version 1.1;namespace urn:oo2;prefix oo2; leaf-list x {type uint16; default 10; default 300;}"
                                   "deviation /x {deviate replace {type uint8;}}}", LYS_IN_YANG, &mod));
-    logbuf_assert("Invalid deviation replacing leaf-list's type - the leaf-list's default value \"300\" does not match the type "
-                  "(Value \"300\" is out of uint8's min/max bounds.). /oo2:{deviation='/x'}");
+    logbuf_assert("Invalid default - value does not fit the type "
+                  "(Value \"300\" is out of uint8's min/max bounds.). /oo2:x");
     assert_int_equal(LY_EVALID, lys_parse_mem(ctx, "module oo3 {namespace urn:oo3;prefix oo3; leaf x {type uint8;}"
                                   "deviation /x {deviate add {default 300;}}}", LYS_IN_YANG, &mod));
-    logbuf_assert("Invalid deviation setting \"default\" property \"300\" which does not fit the type "
-                  "(Value \"300\" is out of uint8's min/max bounds.). /oo3:{deviation='/x'}");
+    logbuf_assert("Invalid default - value does not fit the type "
+                  "(Value \"300\" is out of uint8's min/max bounds.). /oo3:x");
 
 /* TODO recompiling reference object after deviation changes schema tree
     assert_non_null(lys_parse_mem(ctx, "module pp {namespace urn:pp;prefix pp; leaf l { type leafref {path /c/x;}}"
diff --git a/tests/utests/test_xpath.c b/tests/utests/test_xpath.c
index eb595f1..e72c929 100644
--- a/tests/utests/test_xpath.c
+++ b/tests/utests/test_xpath.c
@@ -223,8 +223,6 @@
     "</c>";
     struct lyd_node *tree, *node;
     struct ly_set *set;
-    int dynamic;
-    const char *val_str;
 
     assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, data, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &tree));
     assert_non_null(tree);
@@ -237,9 +235,7 @@
     assert_string_equal(node->schema->name, "l1");
     node = lyd_node_children(node, 0);
     assert_string_equal(node->schema->name, "a");
-    val_str = lyd_value2str((struct lyd_node_term *)node, &dynamic);
-    assert_int_equal(0, dynamic);
-    assert_string_equal(val_str, "a3");
+    assert_string_equal(LYD_CANONICAL(node), "a3");
 
     ly_set_free(set, NULL);
 
@@ -251,9 +247,7 @@
     assert_string_equal(node->schema->name, "ll");
     node = lyd_node_children(node, 0);
     assert_string_equal(node->schema->name, "a");
-    val_str = lyd_value2str((struct lyd_node_term *)node, &dynamic);
-    assert_int_equal(0, dynamic);
-    assert_string_equal(val_str, "val_b");
+    assert_string_equal(LYD_CANONICAL(node), "val_b");
     node = node->next;
     assert_string_equal(node->schema->name, "b");
     assert_null(node->next);
@@ -272,9 +266,7 @@
 
     node = set->objs[0];
     assert_string_equal(node->schema->name, "ll2");
-    val_str = lyd_value2str((struct lyd_node_term *)node, &dynamic);
-    assert_int_equal(0, dynamic);
-    assert_string_equal(val_str, "three");
+    assert_string_equal(LYD_CANONICAL(node), "three");
 
     ly_set_free(set, NULL);
 
diff --git a/tools/re/main.c b/tools/re/main.c
index 2ed63db..8a313f0 100644
--- a/tools/re/main.c
+++ b/tools/re/main.c
@@ -133,6 +133,7 @@
     ssize_t l;
     struct lysc_type *type;
     struct ly_err_item *err = NULL;
+    struct lyd_value storage;
 
     opterr = 0;
     while ((i = getopt_long(argc, argv, "hf:ivVp:", options, &opt_index)) != -1) {
@@ -272,8 +273,11 @@
         goto cleanup;
     }
 
-    type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
-    match = type->plugin->store(ctx, type, str, strlen(str), 0, LY_PREF_JSON, NULL, NULL, NULL, NULL, NULL, &err);
+    type = ((struct lysc_node_leaf *)mod->compiled->data)->type;
+    match = type->plugin->store(ctx, type, str, strlen(str), 0, LY_PREF_JSON, NULL, NULL, NULL, &storage, &err);
+    if ((match == LY_SUCCESS) || (match == LY_EINCOMPLETE)) {
+        storage.realtype->plugin->free(ctx, &storage);
+    }
     if (verbose) {
         for (i = 0; i < patterns_count; i++) {
             fprintf(stdout, "pattern  %d: %s\n", i + 1, patterns[i]);