data tree REFACTOR use common union in all data nodes

Also, now redundant casting removed where possible.
Fixes #1388
diff --git a/src/diff.c b/src/diff.c
index ab37b33..05c79d9 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -102,7 +102,7 @@
         /* find next node parent */
         parent = node;
         while (parent->parent && (!diff_parent || (parent->parent->schema != diff_parent->schema))) {
-            parent = (struct lyd_node *)parent->parent;
+            parent = lyd_parent(parent);
         }
         if (parent == node) {
             /* no more parents to find */
@@ -127,14 +127,14 @@
 
     /* find the first duplicated parent */
     if (!diff_parent) {
-        diff_parent = (struct lyd_node *)dup->parent;
+        diff_parent = lyd_parent(dup);
         while (diff_parent && diff_parent->parent) {
-            diff_parent = (struct lyd_node *)diff_parent->parent;
+            diff_parent = lyd_parent(diff_parent);
         }
     } else {
-        diff_parent = (struct lyd_node *)dup;
+        diff_parent = dup;
         while (diff_parent->parent && (diff_parent->parent->schema == parent->schema)) {
-            diff_parent = (struct lyd_node *)diff_parent->parent;
+            diff_parent = lyd_parent(diff_parent);
         }
     }
 
@@ -754,7 +754,7 @@
     const struct lyd_node *diff_parent;
     const char *str;
 
-    for (diff_parent = diff_node; diff_parent; diff_parent = (struct lyd_node *)diff_parent->parent) {
+    for (diff_parent = diff_node; diff_parent; diff_parent = lyd_parent(diff_parent)) {
         LY_LIST_FOR(diff_parent->meta, meta) {
             if (!strcmp(meta->name, "operation") && !strcmp(meta->annotation->module->name, "yang")) {
                 str = meta->value.canonical;
@@ -810,7 +810,7 @@
         return lyd_insert_child(parent_node, new_node);
     }
 
-    assert(!(*first_node)->parent || ((struct lyd_node *)(*first_node)->parent == parent_node));
+    assert(!(*first_node)->parent || (lyd_parent(*first_node) == parent_node));
 
     if (!lysc_is_userordered(new_node->schema)) {
         /* simple insert */
diff --git a/src/parser_json.c b/src/parser_json.c
index e84ee97..8fd2f06 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -165,7 +165,7 @@
             *prefix_p = onode->name.prefix;
             break;
         }
-        node = (struct lyd_node *)node->parent;
+        node = lyd_parent(node);
     }
     *prefix_len_p = ly_strlen(module_name);
 
@@ -198,7 +198,7 @@
     /* init return value */
     *snode_p = NULL;
 
-    LOG_LOCSET(NULL, (const struct lyd_node *)parent, NULL, NULL);
+    LOG_LOCSET(NULL, &parent->node, NULL, NULL);
 
     /* get the element module */
     if (prefix_len) {
@@ -831,7 +831,7 @@
 {
     if (*node_p) {
         /* insert, keep first pointer correct */
-        lyd_insert_node((struct lyd_node *)parent, first_p, *node_p);
+        lyd_insert_node(&parent->node, first_p, *node_p);
         if (first_p) {
             if (parent) {
                 *first_p = parent->child;
@@ -889,7 +889,7 @@
     }
 
     /* create node */
-    lydjson_get_node_prefix((struct lyd_node *)parent, prefix, prefix_len, &module_name, &module_name_len);
+    lydjson_get_node_prefix(&parent->node, prefix, prefix_len, &module_name, &module_name_len);
     ret = lyd_create_opaq(lydctx->jsonctx->ctx, name, name_len, prefix, prefix_len, module_name, module_name_len, value,
             value_len, &dynamic, LY_PREF_JSON, NULL, type_hint, node_p);
     if (dynamic) {
@@ -1188,7 +1188,7 @@
                 ret = LY_EVALID;
                 goto cleanup;
             }
-            attr_node = (struct lyd_node *)parent;
+            attr_node = &parent->node;
             snode = attr_node->schema;
         }
         ret = lydjson_parse_attribute(lydctx, attr_node, snode, name, name_len, prefix, prefix_len, parent, &status,
@@ -1296,7 +1296,7 @@
     goto cleanup;
 
 representation_error:
-    LOG_LOCSET(NULL, (const struct lyd_node *)parent, NULL, NULL);
+    LOG_LOCSET(NULL, &parent->node, NULL, NULL);
     LOGVAL(ctx, LYVE_SYNTAX_JSON, "The %s \"%s\" is expected to be represented as JSON %s, but input data contains name/%s.",
             lys_nodetype2str(snode->nodetype), snode->name, expected, lyjson_token2str(status));
     LOG_LOCBACK(0, parent ? 1 : 0, 0, 0);
diff --git a/src/parser_lyb.c b/src/parser_lyb.c
index 7fc3ea1..97cb85d 100644
--- a/src/parser_lyb.c
+++ b/src/parser_lyb.c
@@ -880,7 +880,7 @@
     }
 
     /* insert, keep first pointer correct */
-    lyd_insert_node((struct lyd_node *)parent, first, node);
+    lyd_insert_node(&parent->node, first, node);
     while (!parent && (*first)->prev->next) {
         *first = (*first)->prev;
     }
diff --git a/src/parser_xml.c b/src/parser_xml.c
index bfd82b2..2c96b6d 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -603,7 +603,7 @@
     }
 
     /* insert, keep first pointer correct */
-    lyd_insert_node((struct lyd_node *)parent, first_p, node);
+    lyd_insert_node(&parent->node, first_p, node);
     while (!parent && (*first_p)->prev->next) {
         *first_p = (*first_p)->prev;
     }
diff --git a/src/path.c b/src/path.c
index 2d1e868..36ff6d2 100644
--- a/src/path.c
+++ b/src/path.c
@@ -923,7 +923,7 @@
     } else {
         /* absolute path, start from the first top-level sibling */
         while (start->parent) {
-            start = (struct lyd_node *)start->parent;
+            start = lyd_parent(start);
         }
         while (start->prev->next) {
             start = start->prev;
diff --git a/src/printer_data.c b/src/printer_data.c
index 14bb879..b66511d 100644
--- a/src/printer_data.c
+++ b/src/printer_data.c
@@ -59,7 +59,7 @@
     if (root) {
         /* get first top-level sibling */
         while (root->parent) {
-            root = (struct lyd_node *)root->parent;
+            root = lyd_parent(root);
         }
         while (root->prev->next) {
             root = root->prev;
diff --git a/src/printer_json.c b/src/printer_json.c
index 28ee18f..a3fe6fc 100644
--- a/src/printer_json.c
+++ b/src/printer_json.c
@@ -403,7 +403,7 @@
 
     for (attr = node->attr; attr; attr = attr->next) {
         PRINT_COMMA;
-        json_print_member2(ctx, (struct lyd_node *)node, attr->format, &attr->name, 0);
+        json_print_member2(ctx, &node->node, attr->format, &attr->name, 0);
 
         if (attr->hints & (LYD_VALHINT_BOOLEAN | LYD_VALHINT_DECNUM)) {
             ly_print_(ctx->out, "%s", attr->value[0] ? attr->value : "null");
@@ -763,26 +763,24 @@
     ly_bool first = 1, last = 1;
 
     if (node->hints & (LYD_NODEHINT_LIST | LYD_NODEHINT_LEAFLIST)) {
-        const struct lyd_node_opaq *prev = (const struct lyd_node_opaq *)node->prev;
-        const struct lyd_node_opaq *next = (const struct lyd_node_opaq *)node->next;
-        if (prev->next && matching_node((const struct lyd_node *)prev, (const struct lyd_node *)node)) {
+        if (node->prev->next && matching_node(node->prev, &node->node)) {
             first = 0;
         }
-        if (next && matching_node((const struct lyd_node *)node, (const struct lyd_node *)next)) {
+        if (node->next && matching_node(&node->node, node->next)) {
             last = 0;
         }
     }
 
     if (first) {
-        LY_CHECK_RET(json_print_member2(ctx, node->parent, node->format, &node->name, 0));
+        LY_CHECK_RET(json_print_member2(ctx, lyd_parent(&node->node), node->format, &node->name, 0));
 
         if (node->hints & (LYD_NODEHINT_LIST | LYD_NODEHINT_LEAFLIST)) {
-            LY_CHECK_RET(json_print_array_open(ctx, (struct lyd_node *)node));
+            LY_CHECK_RET(json_print_array_open(ctx, &node->node));
             LEVEL_INC;
         }
     }
     if (node->child || (node->hints & (LYD_NODEHINT_LIST | LYD_NODEHINT_LEAFLIST))) {
-        LY_CHECK_RET(json_print_inner(ctx, (struct lyd_node *)node));
+        LY_CHECK_RET(json_print_inner(ctx, &node->node));
         LEVEL_PRINTED;
     } else {
         if (node->hints & LYD_VALHINT_EMPTY) {
diff --git a/src/printer_lyb.c b/src/printer_lyb.c
index 83730f8..2082999 100644
--- a/src/printer_lyb.c
+++ b/src/printer_lyb.c
@@ -919,7 +919,7 @@
     LY_CHECK_RET(lyb_write_start_subtree(out, lybctx->lybctx));
 
     /* write model info first */
-    if (!node->schema && !((struct lyd_node_opaq *)node)->parent) {
+    if (!node->schema && !lyd_parent(node)) {
         LY_CHECK_RET(lyb_print_model(out, NULL, lybctx->lybctx));
     } else if (node->schema && !lysc_data_parent(node->schema)) {
         LY_CHECK_RET(lyb_print_model(out, node->schema->module, lybctx->lybctx));
diff --git a/src/printer_xml.c b/src/printer_xml.c
index 744f5be..086c62b 100644
--- a/src/printer_xml.c
+++ b/src/printer_xml.c
@@ -323,7 +323,7 @@
     ly_bool dynamic;
     const char *value;
 
-    xml_print_node_open(ctx, (struct lyd_node *)node);
+    xml_print_node_open(ctx, &node->node);
     value = ((struct lysc_node_leaf *)node->schema)->type->plugin->print(&node->value, LY_PREF_XML, &ns_list, &dynamic);
 
     /* print namespaces connected with the values's prefixes */
@@ -358,7 +358,7 @@
     LY_ERR ret;
     struct lyd_node *child;
 
-    xml_print_node_open(ctx, (struct lyd_node *)node);
+    xml_print_node_open(ctx, &node->node);
 
     LY_LIST_FOR(node->child, child) {
         if (ly_should_print(child, ctx->options)) {
@@ -394,7 +394,7 @@
     uint32_t prev_opts, prev_lo;
     LY_ERR ret;
 
-    xml_print_node_open(ctx, (struct lyd_node *)node);
+    xml_print_node_open(ctx, &node->node);
 
     if (!any->value.tree) {
         /* no content */
diff --git a/src/tree_data.c b/src/tree_data.c
index d429bdb..2944077 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -175,13 +175,13 @@
         stored = 1;
 
         /* resolve */
-        rc = type->plugin->validate(ctx ? ctx : LYD_CTX(node), type, (struct lyd_node *)node, tree, &val, &err);
+        rc = type->plugin->validate(ctx ? ctx : LYD_CTX(node), type, &node->node, tree, &val, &err);
     }
 
     if (rc) {
         if (err) {
             if (ctx) {
-                LOG_LOCSET(NULL, (const struct lyd_node *)node, NULL, NULL);
+                LOG_LOCSET(NULL, &node->node, NULL, NULL);
                 LOGVAL(ctx, err->vecode, err->msg);
                 LOG_LOCBACK(0, 1, 0, 0);
             }
@@ -219,7 +219,7 @@
     type = ((struct lysc_node_leaf *)node->schema)->type;
 
     /* store the value */
-    LOG_LOCSET(node->schema, (const struct lyd_node *)node, NULL, NULL);
+    LOG_LOCSET(node->schema, &node->node, NULL, NULL);
     ret = lyd_value_store(ctx, &val, type, value, value_len, NULL, LY_PREF_JSON, NULL, LYD_HINT_DATA, node->schema, NULL);
     LOG_LOCBACK(1, 1, 0, 0);
     LY_CHECK_RET(ret);
@@ -535,7 +535,7 @@
     LY_CHECK_ERR_RET(!term, LOGMEM(schema->module->ctx), LY_EMEM);
 
     term->schema = schema;
-    term->prev = (struct lyd_node *)term;
+    term->prev = &term->node;
     term->flags = LYD_NEW;
 
     LOG_LOCSET(schema, NULL, NULL, NULL);
@@ -543,9 +543,9 @@
             value_len, dynamic, format, prefix_data, hints, schema, incomplete);
     LOG_LOCBACK(1, 0, 0, 0);
     LY_CHECK_ERR_RET(ret, free(term), ret);
-    lyd_hash((struct lyd_node *)term);
+    lyd_hash(&term->node);
 
-    *node = (struct lyd_node *)term;
+    *node = &term->node;
     return ret;
 }
 
@@ -563,7 +563,7 @@
     LY_CHECK_ERR_RET(!term, LOGMEM(schema->module->ctx), LY_EMEM);
 
     term->schema = schema;
-    term->prev = (struct lyd_node *)term;
+    term->prev = &term->node;
     term->flags = LYD_NEW;
 
     type = ((struct lysc_node_leaf *)schema)->type;
@@ -573,9 +573,9 @@
         free(term);
         return ret;
     }
-    lyd_hash((struct lyd_node *)term);
+    lyd_hash(&term->node);
 
-    *node = (struct lyd_node *)term;
+    *node = &term->node;
     return ret;
 }
 
@@ -590,7 +590,7 @@
     LY_CHECK_ERR_RET(!in, LOGMEM(schema->module->ctx), LY_EMEM);
 
     in->schema = schema;
-    in->prev = (struct lyd_node *)in;
+    in->prev = &in->node;
     in->flags = LYD_NEW;
     if ((schema->nodetype == LYS_CONTAINER) && !(schema->flags & LYS_PRESENCE)) {
         in->flags |= LYD_DEFAULT;
@@ -598,10 +598,10 @@
 
     /* do not hash list with keys, we need them for the hash */
     if ((schema->nodetype != LYS_LIST) || (schema->flags & LYS_KEYLESS)) {
-        lyd_hash((struct lyd_node *)in);
+        lyd_hash(&in->node);
     }
 
-    *node = (struct lyd_node *)in;
+    *node = &in->node;
     return LY_SUCCESS;
 }
 
@@ -681,7 +681,7 @@
     LY_CHECK_ERR_RET(!any, LOGMEM(schema->module->ctx), LY_EMEM);
 
     any->schema = schema;
-    any->prev = (struct lyd_node *)any;
+    any->prev = &any->node;
     any->flags = LYD_NEW;
 
     /* TODO: convert XML/JSON strings into a opaq data tree */
@@ -691,12 +691,12 @@
         any->value_type = value_type;
     } else {
         any_val.str = value;
-        ret = lyd_any_copy_value((struct lyd_node *)any, &any_val, value_type);
+        ret = lyd_any_copy_value(&any->node, &any_val, value_type);
         LY_CHECK_ERR_RET(ret, free(any), ret);
     }
-    lyd_hash((struct lyd_node *)any);
+    lyd_hash(&any->node);
 
-    *node = (struct lyd_node *)any;
+    *node = &any->node;
     return LY_SUCCESS;
 }
 
@@ -717,7 +717,7 @@
     opaq = calloc(1, sizeof *opaq);
     LY_CHECK_ERR_GOTO(!opaq, LOGMEM(ctx); ret = LY_EMEM, finish);
 
-    opaq->prev = (struct lyd_node *)opaq;
+    opaq->prev = &opaq->node;
     LY_CHECK_GOTO(ret = lydict_insert(ctx, name, name_len, &opaq->name.name), finish);
 
     if (pref_len) {
@@ -740,10 +740,10 @@
 
 finish:
     if (ret) {
-        lyd_free_tree((struct lyd_node *)opaq);
+        lyd_free_tree(&opaq->node);
         ly_free_prefix_data(format, val_prefix_data);
     } else {
-        *node = (struct lyd_node *)opaq;
+        *node = &opaq->node;
     }
     return ret;
 }
@@ -1182,7 +1182,7 @@
 
     /* always clear the default flag */
     if (term->flags & LYD_DEFAULT) {
-        for (parent = term; parent; parent = (struct lyd_node *)parent->parent) {
+        for (parent = term; parent; parent = lyd_parent(parent)) {
             parent->flags &= ~LYD_DEFAULT;
         }
         dflt_change = 1;
@@ -1204,9 +1204,9 @@
         } else if ((term->schema->flags & LYS_KEY) && term->parent) {
             /* list needs to be updated if its key was changed */
             assert(term->parent->schema->nodetype == LYS_LIST);
-            lyd_unlink_hash((struct lyd_node *)term->parent);
-            lyd_hash((struct lyd_node *)term->parent);
-            LY_CHECK_GOTO(ret = lyd_insert_hash((struct lyd_node *)term->parent), cleanup);
+            lyd_unlink_hash(lyd_parent(term));
+            lyd_hash(lyd_parent(term));
+            LY_CHECK_GOTO(ret = lyd_insert_hash(lyd_parent(term)), cleanup);
         } /* else leaf that is not a key, its value is not used for its hash so it does not change */
     }
 
@@ -1623,7 +1623,7 @@
         /* skip added default nodes */
         if (((node->flags & (LYD_DEFAULT | LYD_NEW)) != (LYD_DEFAULT | LYD_NEW)) &&
                 (node->schema->nodetype & LYD_NODE_INNER)) {
-            LY_CHECK_GOTO(ret = lyd_new_implicit_r(node, lyd_node_children_p((struct lyd_node *)node), NULL, NULL, NULL,
+            LY_CHECK_GOTO(ret = lyd_new_implicit_r(node, lyd_node_children_p(node), NULL, NULL, NULL,
                     &node_when, implicit_options, diff), cleanup);
         }
 
@@ -1846,7 +1846,7 @@
         }
         if (par->schema && (par->schema->nodetype == LYS_LIST) && (par->schema->flags & LYS_KEYLESS)) {
             /* rehash key-less list */
-            lyd_hash((struct lyd_node *)par);
+            lyd_hash(&par->node);
         }
     }
 }
@@ -1886,7 +1886,7 @@
         }
         if (par->schema && (par->schema->nodetype == LYS_LIST) && (par->schema->flags & LYS_KEYLESS)) {
             /* rehash key-less list */
-            lyd_hash((struct lyd_node *)par);
+            lyd_hash(&par->node);
         }
     }
 }
@@ -1919,7 +1919,7 @@
         }
         if (par->schema && (par->schema->nodetype == LYS_LIST) && (par->schema->flags & LYS_KEYLESS)) {
             /* rehash key-less list */
-            lyd_hash((struct lyd_node *)par);
+            lyd_hash(&par->node);
         }
     }
 }
@@ -1963,11 +1963,11 @@
             (parent->schema->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_RPC | LYS_ACTION | LYS_NOTIF)));
 
     if (!parent && first_sibling_p && (*first_sibling_p) && (*first_sibling_p)->parent) {
-        parent = (struct lyd_node *)(*first_sibling_p)->parent;
+        parent = lyd_parent(*first_sibling_p);
     }
 
     /* get first sibling */
-    first_sibling = parent ? ((struct lyd_node_inner *)parent)->child : *first_sibling_p;
+    first_sibling = parent ? lyd_child(parent) : *first_sibling_p;
 
     /* find the anchor, our next node, so we can insert before it */
     anchor = lyd_insert_get_next_anchor(first_sibling, node);
@@ -2206,7 +2206,7 @@
         }
 
         /* check for keyless list and update its hash */
-        for (iter = (struct lyd_node *)node->parent; iter; iter = (struct lyd_node *)iter->parent) {
+        for (iter = lyd_parent(node); iter; iter = lyd_parent(iter)) {
             if (iter->schema && (iter->schema->flags & LYS_KEYLESS)) {
                 lyd_hash(iter);
             }
@@ -2245,7 +2245,7 @@
     /* remove default flags from NP containers */
     while (clear_dflt && parent && (parent->schema->nodetype == LYS_CONTAINER) && (parent->flags & LYD_DEFAULT)) {
         parent->flags &= ~LYD_DEFAULT;
-        parent = (struct lyd_node *)parent->parent;
+        parent = lyd_parent(parent);
     }
 }
 
@@ -2474,8 +2474,8 @@
                 }
             }
             if (options & LYD_COMPARE_FULL_RECURSION) {
-                iter1 = ((struct lyd_node_inner *)node1)->child;
-                iter2 = ((struct lyd_node_inner *)node2)->child;
+                iter1 = lyd_child(node1);
+                iter2 = lyd_child(node2);
                 goto all_children_compare;
             }
             return LY_SUCCESS;
@@ -2495,8 +2495,8 @@
             }
             return LY_SUCCESS;
         case LYS_LIST:
-            iter1 = ((struct lyd_node_inner *)node1)->child;
-            iter2 = ((struct lyd_node_inner *)node2)->child;
+            iter1 = lyd_child(node1);
+            iter2 = lyd_child(node2);
 
             if (!(node1->schema->flags & LYS_KEYLESS) && !(options & LYD_COMPARE_FULL_RECURSION)) {
                 /* lists with keys, their equivalence is based on their keys */
@@ -2820,7 +2820,7 @@
             }
         } else {
             /* if there is no local parent, it will be inserted into first */
-            rc = lyd_dup_r(orig, (struct lyd_node *)local_parent, &first, options, first ? NULL : &first);
+            rc = lyd_dup_r(orig, &local_parent->node, &first, options, first ? NULL : &first);
             LY_CHECK_GOTO(rc, error);
         }
         if (nosiblings) {
@@ -2831,7 +2831,7 @@
     /* rehash if needed */
     for ( ; local_parent; local_parent = local_parent->parent) {
         if ((local_parent->schema->nodetype == LYS_LIST) && (local_parent->schema->flags & LYS_KEYLESS)) {
-            lyd_hash((struct lyd_node *)local_parent);
+            lyd_hash(&local_parent->node);
         }
     }
 
@@ -3169,14 +3169,14 @@
     case LYD_PATH_STD:
     case LYD_PATH_STD_NO_LAST_PRED:
         depth = 1;
-        for (iter = node; iter->parent; iter = (const struct lyd_node *)iter->parent) {
+        for (iter = node; iter->parent; iter = lyd_parent(iter)) {
             ++depth;
         }
 
         goto iter_print;
         while (depth) {
             /* find the right node */
-            for (iter = node, i = 1; i < depth; iter = (const struct lyd_node *)iter->parent, ++i) {}
+            for (iter = node, i = 1; i < depth; iter = lyd_parent(iter), ++i) {}
 iter_print:
             /* print prefix and name */
             mod = NULL;
@@ -3303,7 +3303,7 @@
         }
     }
 
-    parent = (struct lyd_node_inner *)siblings->parent;
+    parent = siblings->parent;
     if (parent && parent->schema && parent->children_ht) {
         assert(target->hash);
 
@@ -3386,7 +3386,7 @@
 
     assert(siblings && schema);
 
-    parent = (struct lyd_node_inner *)siblings->parent;
+    parent = siblings->parent;
     if (parent && parent->schema && parent->children_ht) {
         /* calculate our hash */
         hash = dict_hash_multi(0, schema->module->name, strlen(schema->module->name));
diff --git a/src/tree_data.h b/src/tree_data.h
index a5804c9..949faaa 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -326,7 +326,7 @@
     }\
     if (!(LYD_TREE_DFS_next)) { \
         /* no children */ \
-        if ((ELEM) == (struct lyd_node*)(START)) { \
+        if ((ELEM) == (struct lyd_node *)(START)) { \
             /* we are done, (START) has no children */ \
             break; \
         } \
@@ -335,7 +335,7 @@
     } \
     while (!(LYD_TREE_DFS_next)) { \
         /* parent is already processed, go to its sibling */ \
-        (ELEM) = (struct lyd_node*)(ELEM)->parent; \
+        (ELEM) = (struct lyd_node *)(ELEM)->parent; \
         /* no siblings, go back through parents */ \
         if ((ELEM)->parent == (START)->parent) { \
             /* we are done, no next element to process */ \
@@ -498,7 +498,6 @@
     LY_PREFIX_FORMAT format;        /**< format of the attribute and any prefixes, ::LY_PREF_XML or ::LY_PREF_JSON */
     void *val_prefix_data;          /**< format-specific prefix data */
     uint32_t hints;                 /**< additional information about from the data source, see the [hints list](@ref lydhints) */
-
 };
 
 #define LYD_NODE_INNER (LYS_CONTAINER|LYS_LIST|LYS_RPC|LYS_ACTION|LYS_NOTIF) /**< Schema nodetype mask for lyd_node_inner */
@@ -558,20 +557,26 @@
  * @brief Data node structure for the inner data tree nodes - containers, lists, RPCs, actions and Notifications.
  */
 struct lyd_node_inner {
-    uint32_t hash;                   /**< hash of this particular node (module name + schema name + key string values if list or
-                                          hashes of all nodes of subtree in case of keyless list). Note that while hash can be
-                                          used to get know that nodes are not equal, it cannot be used to decide that the
-                                          nodes are equal due to possible collisions. */
-    uint32_t flags;                  /**< [data node flags](@ref dnodeflags) */
-    const struct lysc_node *schema;  /**< pointer to the schema definition of this node */
-    struct lyd_node_inner *parent;   /**< pointer to the parent node, NULL in case of root node */
-    struct lyd_node *next;           /**< pointer to the next sibling node (NULL if there is no one) */
-    struct lyd_node *prev;           /**< pointer to the previous sibling node \note Note that this pointer is
-                                          never NULL. If there is no sibling node, pointer points to the node
-                                          itself. In case of the first node, this pointer points to the last
-                                          node in the list. */
-    struct lyd_meta *meta;           /**< pointer to the list of metadata of this node */
-    void *priv;                      /**< private user data, not used by libyang */
+    union {
+        struct lyd_node node;               /**< implicit cast for the members compatible with ::lyd_node */
+        struct {
+            uint32_t hash;                  /**< hash of this particular node (module name + schema name + key string
+                                                 values if list or hashes of all nodes of subtree in case of keyless
+                                                 list). Note that while hash can be used to get know that nodes are
+                                                 not equal, it cannot be used to decide that the nodes are equal due
+                                                 to possible collisions. */
+            uint32_t flags;                 /**< [data node flags](@ref dnodeflags) */
+            const struct lysc_node *schema; /**< pointer to the schema definition of this node */
+            struct lyd_node_inner *parent;  /**< pointer to the parent node, NULL in case of root node */
+            struct lyd_node *next;          /**< pointer to the next sibling node (NULL if there is no one) */
+            struct lyd_node *prev;          /**< pointer to the previous sibling node \note Note that this pointer is
+                                                 never NULL. If there is no sibling node, pointer points to the node
+                                                 itself. In case of the first node, this pointer points to the last
+                                                 node in the list. */
+            struct lyd_meta *meta;          /**< pointer to the list of metadata of this node */
+            void *priv;                     /**< private user data, not used by libyang */
+        };
+    };                                      /**< common part corresponding to ::lyd_node */
 
     struct lyd_node *child;          /**< pointer to the first child node. */
     struct hash_table *children_ht;  /**< hash table with all the direct children (except keys for a list, lists without keys) */
@@ -582,51 +587,63 @@
  * @brief Data node structure for the terminal data tree nodes - leaves and leaf-lists.
  */
 struct lyd_node_term {
-    uint32_t hash;                   /**< hash of this particular node (module name + schema name + key string values if list or
-                                          hashes of all nodes of subtree in case of keyless list). Note that while hash can be
-                                          used to get know that nodes are not equal, it cannot be used to decide that the
-                                          nodes are equal due to possible collisions. */
-    uint32_t flags;                  /**< [data node flags](@ref dnodeflags) */
-    const struct lysc_node *schema;  /**< pointer to the schema definition of this node */
-    struct lyd_node_inner *parent;   /**< pointer to the parent node, NULL in case of root node */
-    struct lyd_node *next;           /**< pointer to the next sibling node (NULL if there is no one) */
-    struct lyd_node *prev;           /**< pointer to the previous sibling node \note Note that this pointer is
-                                          never NULL. If there is no sibling node, pointer points to the node
-                                          itself. In case of the first node, this pointer points to the last
-                                          node in the list. */
-    struct lyd_meta *meta;           /**< pointer to the list of metadata of this node */
-    void *priv;                      /**< private user data, not used by libyang */
+    union {
+        struct lyd_node node;               /**< implicit cast for the members compatible with ::lyd_node */
+        struct {
+            uint32_t hash;                  /**< hash of this particular node (module name + schema name + key string
+                                                 values if list or hashes of all nodes of subtree in case of keyless
+                                                 list). Note that while hash can be used to get know that nodes are
+                                                 not equal, it cannot be used to decide that the nodes are equal due
+                                                 to possible collisions. */
+            uint32_t flags;                 /**< [data node flags](@ref dnodeflags) */
+            const struct lysc_node *schema; /**< pointer to the schema definition of this node */
+            struct lyd_node_inner *parent;  /**< pointer to the parent node, NULL in case of root node */
+            struct lyd_node *next;          /**< pointer to the next sibling node (NULL if there is no one) */
+            struct lyd_node *prev;          /**< pointer to the previous sibling node \note Note that this pointer is
+                                                 never NULL. If there is no sibling node, pointer points to the node
+                                                 itself. In case of the first node, this pointer points to the last
+                                                 node in the list. */
+            struct lyd_meta *meta;          /**< pointer to the list of metadata of this node */
+            void *priv;                     /**< private user data, not used by libyang */
+        };
+    };                                      /**< common part corresponding to ::lyd_node */
 
     struct lyd_value value;          /**< node's value representation */
 };
 
 /**
- * @brief Data node structure for the anydata data tree nodes - anydatas and anyxmls.
+ * @brief Data node structure for the anydata data tree nodes - anydata or anyxml.
  */
 struct lyd_node_any {
-    uint32_t hash;                   /**< hash of this particular node (module name + schema name + key string values if list or
-                                          hashes of all nodes of subtree in case of keyless list). Note that while hash can be
-                                          used to get know that nodes are not equal, it cannot be used to decide that the
-                                          nodes are equal due to possible collisions. */
-    uint32_t flags;                  /**< [data node flags](@ref dnodeflags) */
-    const struct lysc_node *schema;  /**< pointer to the schema definition of this node */
-    struct lyd_node_inner *parent;   /**< pointer to the parent node, NULL in case of root node */
-    struct lyd_node *next;           /**< pointer to the next sibling node (NULL if there is no one) */
-    struct lyd_node *prev;           /**< pointer to the previous sibling node \note Note that this pointer is
-                                          never NULL. If there is no sibling node, pointer points to the node
-                                          itself. In case of the first node, this pointer points to the last
-                                          node in the list. */
-    struct lyd_meta *meta;           /**< pointer to the list of metadata of this node */
-    void *priv;                      /**< private user data, not used by libyang */
+    union {
+        struct lyd_node node;               /**< implicit cast for the members compatible with ::lyd_node */
+        struct {
+            uint32_t hash;                  /**< hash of this particular node (module name + schema name + key string
+                                                 values if list or hashes of all nodes of subtree in case of keyless
+                                                 list). Note that while hash can be used to get know that nodes are
+                                                 not equal, it cannot be used to decide that the nodes are equal due
+                                                 to possible collisions. */
+            uint32_t flags;                 /**< [data node flags](@ref dnodeflags) */
+            const struct lysc_node *schema; /**< pointer to the schema definition of this node */
+            struct lyd_node_inner *parent;  /**< pointer to the parent node, NULL in case of root node */
+            struct lyd_node *next;          /**< pointer to the next sibling node (NULL if there is no one) */
+            struct lyd_node *prev;          /**< pointer to the previous sibling node \note Note that this pointer is
+                                                 never NULL. If there is no sibling node, pointer points to the node
+                                                 itself. In case of the first node, this pointer points to the last
+                                                 node in the list. */
+            struct lyd_meta *meta;          /**< pointer to the list of metadata of this node */
+            void *priv;                     /**< private user data, not used by libyang */
+        };
+    };                                      /**< common part corresponding to ::lyd_node */
 
     union lyd_any_value {
-        struct lyd_node *tree;       /**< data tree */
-        const char *str;             /**< Generic string data */
-        const char *xml;             /**< Serialized XML data */
-        const char *json;            /**< I-JSON encoded string */
-        char *mem;                   /**< LYD_ANYDATA_LYB memory chunk */
-    } value;                         /**< pointer to the stored value representation of the anydata/anyxml node */
-    LYD_ANYDATA_VALUETYPE value_type;/**< type of the data stored as ::lyd_node_any.value */
+        struct lyd_node *tree;          /**< data tree */
+        const char *str;                /**< Generic string data */
+        const char *xml;                /**< Serialized XML data */
+        const char *json;               /**< I-JSON encoded string */
+        char *mem;                      /**< LYD_ANYDATA_LYB memory chunk */
+    } value;                            /**< pointer to the stored value representation of the anydata/anyxml node */
+    LYD_ANYDATA_VALUETYPE value_type;   /**< type of the data stored as ::lyd_node_any.value */
 };
 
 /**
@@ -690,14 +707,22 @@
  * @brief Data node structure for unparsed (opaque) nodes.
  */
 struct lyd_node_opaq {
-    uint32_t hash;                  /**< always 0 */
-    uint32_t flags;                 /**< always 0 */
-    const struct lysc_node *schema; /**< always NULL */
-    struct lyd_node *parent;        /**< pointer to the parent node (NULL in case of root node) */
-    struct lyd_node *next;          /**< pointer to the next sibling node (NULL if there is no one) */
-    struct lyd_node *prev;          /**< pointer to the previous sibling node (last sibling if there is none) */
-    struct lyd_attr *attr;          /**< pointer to the list of generic attributes of this node */
-    void *priv;                     /**< private user data, not used by libyang */
+    union {
+        struct lyd_node node;               /**< implicit cast for the members compatible with ::lyd_node */
+        struct {
+            uint32_t hash;                  /**< always 0 */
+            uint32_t flags;                 /**< always 0 */
+            const struct lysc_node *schema; /**< always NULL */
+            struct lyd_node_inner *parent;  /**< pointer to the parent node, NULL in case of root node */
+            struct lyd_node *next;          /**< pointer to the next sibling node (NULL if there is no one) */
+            struct lyd_node *prev;          /**< pointer to the previous sibling node \note Note that this pointer is
+                                                 never NULL. If there is no sibling node, pointer points to the node
+                                                 itself. In case of the first node, this pointer points to the last
+                                                 node in the list. */
+            struct lyd_meta *meta;          /**< always NULL */
+            void *priv;                     /**< private user data, not used by libyang */
+        };
+    };                                      /**< common part corresponding to ::lyd_node */
 
     struct lyd_node *child;         /**< pointer to the child node (compatible with ::lyd_node_inner) */
 
@@ -707,6 +732,7 @@
     void *val_prefix_data;          /**< format-specific prefix data */
     uint32_t hints;                 /**< additional information about from the data source, see the [hints list](@ref lydhints) */
 
+    struct lyd_attr *attr;          /**< pointer to the list of generic attributes of this node */
     const struct ly_ctx *ctx;       /**< libyang context */
 };
 
diff --git a/src/tree_data_free.c b/src/tree_data_free.c
index 274897a..cb5a6c5 100644
--- a/src/tree_data_free.c
+++ b/src/tree_data_free.c
@@ -214,7 +214,7 @@
 
     /* get the first (top-level) sibling */
     if (top) {
-        for ( ; node->parent; node = (struct lyd_node *)node->parent) {}
+        for ( ; node->parent; node = lyd_parent(node)) {}
     }
     while (node->prev->next) {
         node = node->prev;
diff --git a/src/tree_data_hash.c b/src/tree_data_hash.c
index 523c85d..921a1a0 100644
--- a/src/tree_data_hash.c
+++ b/src/tree_data_hash.c
@@ -34,7 +34,7 @@
         switch (iter->schema->nodetype) {
         case LYS_CONTAINER:
         case LYS_LIST:
-            lyd_hash_keyless_list_dfs(((struct lyd_node_inner *)iter)->child, hash);
+            lyd_hash_keyless_list_dfs(lyd_child(iter), hash);
             break;
         case LYS_LEAFLIST:
         case LYS_ANYXML:
diff --git a/src/tree_data_helpers.c b/src/tree_data_helpers.c
index 78f53af..02bc433 100644
--- a/src/tree_data_helpers.c
+++ b/src/tree_data_helpers.c
@@ -92,7 +92,7 @@
         return NULL;
     }
 
-    return (struct lyd_node *)(node)->parent;
+    return &node->parent->node;
 }
 
 API struct lyd_node *
@@ -106,7 +106,7 @@
 
     if (!node->schema) {
         /* opaq node */
-        return ((struct lyd_node_opaq *)(node))->child;
+        return ((struct lyd_node_opaq *)node)->child;
     }
 
     children = lyd_node_children_p((struct lyd_node *)node);
@@ -128,7 +128,7 @@
 
     if (!node->schema) {
         /* opaq node */
-        return ((struct lyd_node_opaq *)(node))->child;
+        return ((struct lyd_node_opaq *)node)->child;
     }
 
     children = lyd_node_children_p((struct lyd_node *)node);
diff --git a/src/validation.c b/src/validation.c
index 9e2d105..c31c456 100644
--- a/src/validation.c
+++ b/src/validation.c
@@ -124,7 +124,7 @@
                 ctx_node = node;
             } else {
                 assert((!when->context && !node->parent) || (when->context == node->parent->schema));
-                ctx_node = (struct lyd_node *)node->parent;
+                ctx_node = lyd_parent(node);
             }
 
             /* evaluate when */
@@ -252,8 +252,8 @@
             struct lysc_type *type = ((struct lysc_node_leaf *)node->schema)->type;
 
             /* resolve the value of the node */
-            LOG_LOCSET(node->schema, (struct lyd_node *)node, NULL, NULL);
-            ret = lyd_value_validate_incomplete(LYD_CTX(node), type, &node->value, (struct lyd_node *)node, *tree);
+            LOG_LOCSET(node->schema, &node->node, NULL, NULL);
+            ret = lyd_value_validate_incomplete(LYD_CTX(node), type, &node->value, &node->node, *tree);
             LOG_LOCBACK(node->schema ? 1 : 0, 1, 0, 0);
             LY_CHECK_RET(ret);
 
@@ -1181,7 +1181,7 @@
     }
 
     /* find first top-level node */
-    for (tree = node; tree->parent; tree = (struct lyd_node *)tree->parent) {}
+    for (tree = node; tree->parent; tree = lyd_parent(tree)) {}
     while (tree->prev->next) {
         tree = tree->prev;
     }
@@ -1309,11 +1309,10 @@
             LY_CHECK_RET(ly_set_add(node_types, (void *)node, 1, NULL));
         } else if (node->schema->nodetype & LYD_NODE_INNER) {
             /* new node validation, autodelete */
-            LY_CHECK_RET(lyd_validate_new(lyd_node_children_p((struct lyd_node *)node), node->schema, NULL, diff));
+            LY_CHECK_RET(lyd_validate_new(lyd_node_children_p(node), node->schema, NULL, diff));
 
             /* add nested defaults */
-            LY_CHECK_RET(lyd_new_implicit_r(node, lyd_node_children_p((struct lyd_node *)node), NULL, NULL, NULL,
-                    NULL, impl_opts, diff));
+            LY_CHECK_RET(lyd_new_implicit_r(node, lyd_node_children_p(node), NULL, NULL, NULL, NULL, impl_opts, diff));
         }
 
         if (lysc_node_when(node->schema)) {
@@ -1446,7 +1445,7 @@
 
     /* learn op depth (top-level being depth 0) */
     op_depth = 0;
-    for (op_iter = op_node; op_iter != op_tree; op_iter = (struct lyd_node *)op_iter->parent) {
+    for (op_iter = op_node; op_iter != op_tree; op_iter = lyd_parent(op_iter)) {
         ++op_depth;
     }
 
@@ -1469,7 +1468,7 @@
         /* find next op parent */
         op_iter = op_node;
         for (i = 0; i < cur_depth; ++i) {
-            op_iter = (struct lyd_node *)op_iter->parent;
+            op_iter = lyd_parent(op_iter);
         }
     }
 
@@ -1521,7 +1520,7 @@
 
     /* move op_tree to top-level node */
     while (op_tree->parent) {
-        op_tree = (struct lyd_node *)op_tree->parent;
+        op_tree = lyd_parent(op_tree);
     }
 
     /* merge op_tree into tree */
diff --git a/src/xpath.c b/src/xpath.c
index 8f10af7..9dc8d24 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -193,11 +193,10 @@
                 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ROOT CONFIG", i + 1, item->pos);
                 break;
             case LYXP_NODE_ELEM:
-                if ((item->node->schema->nodetype == LYS_LIST) &&
-                        (((struct lyd_node_inner *)item->node)->child->schema->nodetype == LYS_LEAF)) {
+                if ((item->node->schema->nodetype == LYS_LIST) && (lyd_child(item->node)->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, LYD_CANON_VALUE(lyd_child(item->node)));
-                } else if (((struct lyd_node_inner *)item->node)->schema->nodetype == LYS_LEAFLIST) {
+                } else if (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, LYD_CANON_VALUE(item->node));
                 } else {
@@ -1611,7 +1610,7 @@
     }
 
     /* find first top-level node to be used as anchor for positions */
-    for (root = set->cur_node; root->parent; root = (const struct lyd_node *)root->parent) {}
+    for (root = set->cur_node; root->parent; root = lyd_parent(root)) {}
     for ( ; root->prev->next; root = root->prev) {}
 
     /* fill positions */
@@ -1731,7 +1730,7 @@
     }
 
     /* find first top-level node to be used as anchor for positions */
-    for (root = trg->cur_node; root->parent; root = (const struct lyd_node *)root->parent) {}
+    for (root = trg->cur_node; root->parent; root = lyd_parent(root)) {}
     for ( ; root->prev->next; root = root->prev) {}
 
     /* fill positions */
@@ -3729,8 +3728,8 @@
         if (sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
             if (sleaf->type->basetype == LY_TYPE_LEAFREF) {
                 /* find leafref target */
-                if (ly_type_find_leafref((struct lysc_type_leafref *)sleaf->type, (struct lyd_node *)leaf,
-                        &leaf->value, set->tree, &node, &errmsg)) {
+                if (ly_type_find_leafref((struct lysc_type_leafref *)sleaf->type, &leaf->node, &leaf->value, set->tree,
+                        &node, &errmsg)) {
                     LOGERR(set->ctx, LY_EVALID, errmsg);
                     free(errmsg);
                     return LY_EVALID;
@@ -4040,7 +4039,7 @@
     }
 
     /* find lang metadata */
-    for ( ; node; node = (struct lyd_node *)node->parent) {
+    for ( ; node; node = lyd_parent(node)) {
         for (meta = node->meta; meta; meta = meta->next) {
             /* annotations */
             if (meta->name && !strcmp(meta->name, "lang") && !strcmp(meta->annotation->module->name, "xml")) {
@@ -5772,12 +5771,12 @@
             }
             while (!next) {
                 /* no siblings, go back through the parents */
-                if ((struct lyd_node *)elem->parent == start) {
+                if (lyd_parent(elem) == start) {
                     /* we are done, no next element to process */
                     break;
                 }
                 /* parent is already processed, go to its sibling */
-                elem = (struct lyd_node *)elem->parent;
+                elem = lyd_parent(elem);
                 next = elem->next;
             }
         }
@@ -6321,7 +6320,7 @@
         node = set->val.nodes[i].node;
 
         if (set->val.nodes[i].type == LYXP_NODE_ELEM) {
-            new_node = (struct lyd_node *)node->parent;
+            new_node = lyd_parent(node);
         } else if (set->val.nodes[i].type == LYXP_NODE_TEXT) {
             new_node = node;
         } else if (set->val.nodes[i].type == LYXP_NODE_META) {
@@ -6748,8 +6747,8 @@
             /* remember the node context position for position() and context size for last(),
              * predicates should always be evaluated with respect to the child axis (since we do
              * not support explicit axes) so we assign positions based on their parents */
-            if (parent_pos_pred && ((struct lyd_node *)set->val.nodes[i].node->parent != orig_parent)) {
-                orig_parent = (struct lyd_node *)set->val.nodes[i].node->parent;
+            if (parent_pos_pred && (lyd_parent(set->val.nodes[i].node) != orig_parent)) {
+                orig_parent = lyd_parent(set->val.nodes[i].node);
                 orig_pos = 1;
             } else {
                 ++orig_pos;