schema tree NEW when cyclic ref check
diff --git a/src/common.h b/src/common.h
index dc71b11..a3403b5 100644
--- a/src/common.h
+++ b/src/common.h
@@ -172,62 +172,64 @@
 /* default maximum characters to print in LY_VCODE_INCHILDSTMT */
 #define LY_VCODE_INSTREXP_MAXLEN 20
 
-#define LY_VCODE_INCHAR      LYVE_SYNTAX, "Invalid character 0x%x."
-#define LY_VCODE_INSTREXP    LYVE_SYNTAX, "Invalid character sequence \"%.*s\", expected %s."
-#define LY_VCODE_EOF         LYVE_SYNTAX, "Unexpected end-of-input."
-#define LY_VCODE_NTERM       LYVE_SYNTAX, "%s not terminated."
-#define LY_VCODE_NSUPP       LYVE_SYNTAX, "%s not supported."
-#define LY_VCODE_MOD_SUBOMD  LYVE_SYNTAX, "Invalid keyword \"%s\", expected \"module\" or \"submodule\"."
-#define LY_VCODE_TRAILING_MOD LYVE_SYNTAX, "Trailing garbage \"%.*s%s\" after module, expected end-of-input."
+#define LY_VCODE_INCHAR         LYVE_SYNTAX, "Invalid character 0x%x."
+#define LY_VCODE_INSTREXP       LYVE_SYNTAX, "Invalid character sequence \"%.*s\", expected %s."
+#define LY_VCODE_EOF            LYVE_SYNTAX, "Unexpected end-of-input."
+#define LY_VCODE_NTERM          LYVE_SYNTAX, "%s not terminated."
+#define LY_VCODE_NSUPP          LYVE_SYNTAX, "%s not supported."
+#define LY_VCODE_MOD_SUBOMD     LYVE_SYNTAX, "Invalid keyword \"%s\", expected \"module\" or \"submodule\"."
+#define LY_VCODE_TRAILING_MOD   LYVE_SYNTAX, "Trailing garbage \"%.*s%s\" after module, expected end-of-input."
 #define LY_VCODE_TRAILING_SUBMOD LYVE_SYNTAX, "Trailing garbage \"%.*s%s\" after submodule, expected end-of-input."
 
-#define LY_VCODE_INVAL_MINMAX LYVE_SEMANTICS, "Invalid combination of min-elements and max-elements: min value %u is bigger than the max value %u."
+#define LY_VCODE_INVAL_MINMAX   LYVE_SEMANTICS, "Invalid combination of min-elements and max-elements: min value %u is bigger than the max value %u."
+#define LY_VCODE_CIRC_WHEN      LYVE_SEMANTICS, "When condition of \"%s\" includes a self-reference (referenced by when of \"%s\")."
 
-#define LY_VCODE_INSTMT      LYVE_SYNTAX_YANG, "Invalid keyword \"%s\"."
-#define LY_VCODE_INCHILDSTMT LYVE_SYNTAX_YANG, "Invalid keyword \"%s\" as a child of \"%s\"."
-#define LY_VCODE_INCHILDSTMT2 LYVE_SYNTAX_YANG, "Invalid keyword \"%s\" as a child of \"%s\" - the statement is allowed only in YANG 1.1 modules."
+#define LY_VCODE_INSTMT         LYVE_SYNTAX_YANG, "Invalid keyword \"%s\"."
+#define LY_VCODE_INCHILDSTMT    LYVE_SYNTAX_YANG, "Invalid keyword \"%s\" as a child of \"%s\"."
+#define LY_VCODE_INCHILDSTMT2   LYVE_SYNTAX_YANG, "Invalid keyword \"%s\" as a child of \"%s\" - the statement is allowed only in YANG 1.1 modules."
 #define LY_VCODE_INCHILDSTMSCOMB LYVE_SYNTAX_YANG, "Invalid combination of keywords \"%s\" and \"%s\" as substatements of \"%s\"."
-#define LY_VCODE_DUPSTMT     LYVE_SYNTAX_YANG, "Duplicate keyword \"%s\"."
-#define LY_VCODE_DUPIDENT    LYVE_SYNTAX_YANG, "Duplicate identifier \"%s\" of %s statement."
-#define LY_VCODE_INVAL       LYVE_SYNTAX_YANG, "Invalid value \"%.*s\" of \"%s\"."
-#define LY_VCODE_MISSTMT     LYVE_SYNTAX_YANG, "Missing mandatory keyword \"%s\" as a child of \"%s\"."
-#define LY_VCODE_MISSCHILDSTMT LYVE_SYNTAX_YANG, "Missing %s substatement for %s%s."
-#define LY_VCODE_INORD       LYVE_SYNTAX_YANG, "Invalid keyword \"%s\", it cannot appear after \"%s\"."
-#define LY_VCODE_OOB         LYVE_SYNTAX_YANG, "Value \"%.*s\" is out of \"%s\" bounds."
-#define LY_VCODE_INDEV       LYVE_SYNTAX_YANG, "Deviate \"%s\" does not support keyword \"%s\"."
-#define LY_VCODE_INREGEXP    LYVE_SYNTAX_YANG, "Regular expression \"%s\" is not valid (\"%s\": %s)."
+#define LY_VCODE_DUPSTMT        LYVE_SYNTAX_YANG, "Duplicate keyword \"%s\"."
+#define LY_VCODE_DUPIDENT       LYVE_SYNTAX_YANG, "Duplicate identifier \"%s\" of %s statement."
+#define LY_VCODE_INVAL          LYVE_SYNTAX_YANG, "Invalid value \"%.*s\" of \"%s\"."
+#define LY_VCODE_MISSTMT        LYVE_SYNTAX_YANG, "Missing mandatory keyword \"%s\" as a child of \"%s\"."
+#define LY_VCODE_MISSCHILDSTMT  LYVE_SYNTAX_YANG, "Missing %s substatement for %s%s."
+#define LY_VCODE_INORD          LYVE_SYNTAX_YANG, "Invalid keyword \"%s\", it cannot appear after \"%s\"."
+#define LY_VCODE_OOB            LYVE_SYNTAX_YANG, "Value \"%.*s\" is out of \"%s\" bounds."
+#define LY_VCODE_INDEV          LYVE_SYNTAX_YANG, "Deviate \"%s\" does not support keyword \"%s\"."
+#define LY_VCODE_INREGEXP       LYVE_SYNTAX_YANG, "Regular expression \"%s\" is not valid (\"%s\": %s)."
 
-#define LY_VCODE_INSUBELEM2   LYVE_SYNTAX_YIN, "Invalid sub-elemnt \"%s\" of \"%s\" element - this sub-element is allowed only in modules with version 1.1 or newer."
-#define LY_VCODE_INVAL_YIN   LYVE_SYNTAX_YIN, "Invalid value \"%s\" of \"%s\" attribute in \"%s\" element."
-#define LY_VCODE_UNEXP_SUBELEM LYVE_SYNTAX_YIN, "Unexpected sub-element \"%.*s\" of \"%s\" element."
-#define LY_VCODE_INDEV_YIN   LYVE_SYNTAX_YIN, "Deviate of this type doesn't allow \"%s\" as it's sub-element."
-#define LY_VCODE_INORDER_YIN LYVE_SYNTAX_YIN, "Invalid order of %s\'s sub-elements \"%s\" can't appear after \"%s\"."
-#define LY_VCODE_OOB_YIN      LYVE_SYNTAX_YIN, "Value \"%s\" of \"%s\" attribute in \"%s\" element is out of bounds."
+#define LY_VCODE_INSUBELEM2     LYVE_SYNTAX_YIN, "Invalid sub-elemnt \"%s\" of \"%s\" element - this sub-element is allowed only in modules with version 1.1 or newer."
+#define LY_VCODE_INVAL_YIN      LYVE_SYNTAX_YIN, "Invalid value \"%s\" of \"%s\" attribute in \"%s\" element."
+#define LY_VCODE_UNEXP_SUBELEM  LYVE_SYNTAX_YIN, "Unexpected sub-element \"%.*s\" of \"%s\" element."
+#define LY_VCODE_INDEV_YIN      LYVE_SYNTAX_YIN, "Deviate of this type doesn't allow \"%s\" as it's sub-element."
+#define LY_VCODE_INORDER_YIN    LYVE_SYNTAX_YIN, "Invalid order of %s\'s sub-elements \"%s\" can't appear after \"%s\"."
+#define LY_VCODE_OOB_YIN        LYVE_SYNTAX_YIN, "Value \"%s\" of \"%s\" attribute in \"%s\" element is out of bounds."
 #define LY_VCODE_INCHILDSTMSCOMB_YIN LYVE_SYNTAX_YIN, "Invalid combination of sub-elemnts \"%s\" and \"%s\" in \"%s\" element."
-#define LY_VCODE_DUP_ATTR LYVE_SYNTAX_YIN, "Duplicit definition of \"%s\" attribute in \"%s\" element."
-#define LY_VCODE_UNEXP_ATTR LYVE_SYNTAX_YIN, "Unexpected attribute \"%.*s\" of \"%s\" element."
-#define LY_VCODE_MAND_SUBELEM LYVE_SYNTAX_YIN, "Missing mandatory sub-element \"%s\" of \"%s\" element."
-#define LY_VCODE_FIRT_SUBELEM LYVE_SYNTAX_YIN, "Sub-element \"%s\" of \"%s\" element must be defined as it's first sub-element."
-#define LY_VCODE_NAME_COL LYVE_SYNTAX_YIN, "Name collision between module and submodule of name \"%s\"."
-#define LY_VCODE_SUBELEM_REDEF LYVE_SYNTAX_YIN, "Redefinition of \"%s\" sub-element in \"%s\" element."
+#define LY_VCODE_DUP_ATTR       LYVE_SYNTAX_YIN, "Duplicit definition of \"%s\" attribute in \"%s\" element."
+#define LY_VCODE_UNEXP_ATTR     LYVE_SYNTAX_YIN, "Unexpected attribute \"%.*s\" of \"%s\" element."
+#define LY_VCODE_MAND_SUBELEM   LYVE_SYNTAX_YIN, "Missing mandatory sub-element \"%s\" of \"%s\" element."
+#define LY_VCODE_FIRT_SUBELEM   LYVE_SYNTAX_YIN, "Sub-element \"%s\" of \"%s\" element must be defined as it's first sub-element."
+#define LY_VCODE_NAME_COL       LYVE_SYNTAX_YIN, "Name collision between module and submodule of name \"%s\"."
+#define LY_VCODE_SUBELEM_REDEF  LYVE_SYNTAX_YIN, "Redefinition of \"%s\" sub-element in \"%s\" element."
 
-#define LY_VCODE_XP_EOE      LYVE_XPATH, "Unterminated string delimited with %c (%.15s)."
-#define LY_VCODE_XP_INEXPR   LYVE_XPATH, "Invalid character number %u of expression \'%s\'."
-#define LY_VCODE_XP_DUMMY    LYVE_XPATH, "Accessing the value of the dummy node \"%s\"."
-#define LY_VCODE_XP_EOF      LYVE_XPATH, "Unexpected XPath expression end."
-#define LY_VCODE_XP_INTOK    LYVE_XPATH, "Unexpected XPath token %s (%.15s)."
-#define LY_VCODE_XP_INFUNC   LYVE_XPATH, "Unknown XPath function \"%.*s\"."
-#define LY_VCODE_XP_INARGCOUNT LYVE_XPATH, "Invalid number of arguments (%d) for the XPath function %.*s."
-#define LY_VCODE_XP_INARGTYPE LYVE_XPATH, "Wrong type of argument #%d (%s) for the XPath function %s."
-#define LY_VCODE_XP_INCTX    LYVE_XPATH, "Invalid context type %s in %s."
-#define LY_VCODE_XP_DUMMY    LYVE_XPATH, "Accessing the value of the dummy node \"%s\"."
-#define LY_VCODE_XP_INOP_1   LYVE_XPATH, "Cannot apply XPath operation %s on %s."
-#define LY_VCODE_XP_INOP_2   LYVE_XPATH, "Cannot apply XPath operation %s on %s and %s."
-#define LY_VCODE_XP_INMOD    LYVE_XPATH, "Unknown module \"%.*s\"."
+#define LY_VCODE_XP_EOE         LYVE_XPATH, "Unterminated string delimited with %c (%.15s)."
+#define LY_VCODE_XP_INEXPR      LYVE_XPATH, "Invalid character number %u of expression \'%s\'."
+#define LY_VCODE_XP_EOF         LYVE_XPATH, "Unexpected XPath expression end."
+#define LY_VCODE_XP_INTOK       LYVE_XPATH, "Unexpected XPath token %s (%.15s)."
+#define LY_VCODE_XP_INFUNC      LYVE_XPATH, "Unknown XPath function \"%.*s\"."
+#define LY_VCODE_XP_INARGCOUNT  LYVE_XPATH, "Invalid number of arguments (%d) for the XPath function %.*s."
+#define LY_VCODE_XP_INARGTYPE   LYVE_XPATH, "Wrong type of argument #%d (%s) for the XPath function %s."
+#define LY_VCODE_XP_INCTX       LYVE_XPATH, "Invalid context type %s in %s."
+#define LY_VCODE_XP_DUMMY       LYVE_XPATH, "Accessing the value of the dummy node \"%s\"."
+#define LY_VCODE_XP_INOP_1      LYVE_XPATH, "Cannot apply XPath operation %s on %s."
+#define LY_VCODE_XP_INOP_2      LYVE_XPATH, "Cannot apply XPath operation %s on %s and %s."
+#define LY_VCODE_XP_INMOD       LYVE_XPATH, "Unknown module \"%.*s\"."
 
-#define LY_VCODE_DEV_NODETYPE LYVE_REFERENCE, "Invalid deviation of %s node - it is not possible to %s \"%s\" property."
+#define LY_VCODE_DEV_NODETYPE   LYVE_REFERENCE, "Invalid deviation of %s node - it is not possible to %s \"%s\" property."
 #define LY_VCODE_DEV_NOT_PRESENT LYVE_REFERENCE, "Invalid deviation %s \"%s\" property \"%s\" which is not present."
 
+#define LY_VCODE_NOWHEN         LYVE_DATA, "When condition \"%s\" not satisfied."
+
 /******************************************************************************
  * Context
  *****************************************************************************/
diff --git a/src/log.h b/src/log.h
index c7ee0a3..e5f54b7 100644
--- a/src/log.h
+++ b/src/log.h
@@ -172,7 +172,7 @@
     LYVE_XPATH,        /**< invalid XPath expression */
     LYVE_SEMANTICS,    /**< generic semantic error */
     LYVE_SYNTAX_XML,   /**< XML-related syntax error */
-    LYVE_RESTRICTION   /**< YANG data does not reflect some of the module restrictions */
+    LYVE_DATA,         /**< YANG data does not reflect some of the module restrictions */
 } LY_VECODE;
 
 /**
diff --git a/src/parser_xml.c b/src/parser_xml.c
index 2b4e625..bf7c6ab 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -47,6 +47,7 @@
     char path[LYD_PARSER_BUFSIZE];   /**< buffer for the generated path */
     struct ly_set incomplete_type_validation; /**< set of nodes validated with LY_EINCOMPLETE result */
     struct ly_set incomplete_type_validation_attrs; /**< set of attributes validated with LY_EINCOMPLETE result */
+    struct ly_set when_check;        /**< set of nodes with "when" conditions */
 };
 
 /**
@@ -289,7 +290,7 @@
         switch (snode->nodetype) {
         case LYS_ACTION:
             if ((ctx->options & LYD_OPT_TYPEMASK) != LYD_OPT_RPC) {
-                LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_RESTRICTION, "Unexpected RPC/action element \"%.*s\" in %s data set.",
+                LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_DATA, "Unexpected RPC/action element \"%.*s\" in %s data set.",
                        name_len, name, lyd_parse_options_type2str(ctx->options & LYD_OPT_TYPEMASK));
                 goto error;
             }
@@ -297,7 +298,7 @@
             break;
         case LYS_NOTIF:
             if ((ctx->options & LYD_OPT_TYPEMASK) != LYD_OPT_RPC) {
-                LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_RESTRICTION, "Unexpected Notification element \"%.*s\" in %s data set.",
+                LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_DATA, "Unexpected Notification element \"%.*s\" in %s data set.",
                        name_len, name, lyd_parse_options_type2str(ctx->options));
                 goto error;
             }
@@ -372,7 +373,7 @@
                 if (cur->next) {
                     last = prev;
                     if (ctx->options & LYD_OPT_STRICT) {
-                        LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_RESTRICTION, "Invalid position of the key \"%.*s\" in a list.",
+                        LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_DATA, "Invalid position of the key \"%.*s\" in a list.",
                                name_len, name);
                         goto error;
                     } else {
diff --git a/src/plugins_types.c b/src/plugins_types.c
index feb02f8..aa34d2e 100644
--- a/src/plugins_types.c
+++ b/src/plugins_types.c
@@ -143,7 +143,7 @@
     }
 
 error:
-    *err = ly_err_new(LY_LLERR, LY_EINVAL, LYVE_RESTRICTION, errmsg, NULL, NULL);
+    *err = ly_err_new(LY_LLERR, LY_EINVAL, LYVE_DATA, errmsg, NULL, NULL);
     return LY_EVALID;
 }
 
@@ -230,7 +230,7 @@
     }
 
 error:
-    *err = ly_err_new(LY_LLERR, LY_EINVAL, LYVE_RESTRICTION, errmsg, NULL, NULL);
+    *err = ly_err_new(LY_LLERR, LY_EINVAL, LYVE_DATA, errmsg, NULL, NULL);
     return LY_EVALID;
 }
 
@@ -330,7 +330,7 @@
 
 error:
     if (errmsg) {
-        *err = ly_err_new(LY_LLERR, LY_EINVAL, LYVE_RESTRICTION, errmsg, NULL, NULL);
+        *err = ly_err_new(LY_LLERR, LY_EINVAL, LYVE_DATA, errmsg, NULL, NULL);
     }
     return rc;
 }
@@ -438,7 +438,7 @@
     return LY_SUCCESS;
 
 error:
-    *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_RESTRICTION, errmsg, NULL, range->eapptag ? strdup(range->eapptag) : NULL);
+    *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_DATA, errmsg, NULL, range->eapptag ? strdup(range->eapptag) : NULL);
     return LY_EVALID;
 }
 
@@ -647,7 +647,7 @@
     }
 
     if (!value || !value[0] || !value_len) {
-        *err = ly_err_new(LY_LLERR, LY_EINVAL, LYVE_RESTRICTION, strdup("Invalid empty decimal64 value."), NULL, NULL);
+        *err = ly_err_new(LY_LLERR, LY_EINVAL, LYVE_DATA, strdup("Invalid empty decimal64 value."), NULL, NULL);
         return LY_EVALID;
     }
 
@@ -811,7 +811,7 @@
 
 error:
     if (!*err) {
-        *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_RESTRICTION, errmsg, NULL, NULL);
+        *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_DATA, errmsg, NULL, NULL);
     }
     return (*err)->no;
 }
@@ -1003,7 +1003,7 @@
     return LY_SUCCESS;
 error:
     if (errmsg) {
-        *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_RESTRICTION, errmsg, NULL, NULL);
+        *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_DATA, errmsg, NULL, NULL);
     }
     ly_set_free(items, NULL);
     ly_set_free(items_ordered, NULL);
@@ -1105,7 +1105,7 @@
 
 error:
     if (errmsg) {
-        *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_RESTRICTION, errmsg, NULL, NULL);
+        *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_DATA, errmsg, NULL, NULL);
     }
     return LY_EVALID;
 }
@@ -1145,7 +1145,7 @@
     } else {
         char *errmsg;
         asprintf(&errmsg, "Invalid boolean value \"%.*s\".", (int)value_len, value);
-        *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_RESTRICTION, errmsg, NULL, NULL);
+        *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_DATA, errmsg, NULL, NULL);
         return LY_EVALID;
     }
 
@@ -1195,7 +1195,7 @@
     if (value_len) {
         char *errmsg;
         asprintf(&errmsg, "Invalid empty value \"%.*s\".", (int)value_len, value);
-        *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_RESTRICTION, errmsg, NULL, NULL);
+        *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_DATA, errmsg, NULL, NULL);
         return LY_EVALID;
     }
 
@@ -1326,7 +1326,7 @@
     return LY_SUCCESS;
 
 error:
-    *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_RESTRICTION, errmsg, NULL, NULL);
+    *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_DATA, errmsg, NULL, NULL);
     return LY_EVALID;
 }
 
@@ -1950,7 +1950,7 @@
     lyd_value_free_path(ctx, target);
 
     if (!*err) {
-        *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_RESTRICTION, errmsg, NULL, NULL);
+        *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_DATA, errmsg, NULL, NULL);
     }
     return ret;
 }
@@ -2413,7 +2413,7 @@
 
 error:
     if (!*err) {
-        *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_RESTRICTION, errmsg, NULL, NULL);
+        *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_DATA, errmsg, NULL, NULL);
     }
     if (storage_dummy) {
         storage->realtype->plugin->free(ctx, storage);
@@ -2559,7 +2559,7 @@
 error:
 
     if (!*err) {
-        *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_RESTRICTION, errmsg, NULL, NULL);
+        *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_DATA, errmsg, NULL, NULL);
     }
     LY_ARRAY_FOR(subvalue->prefixes, u) {
         lydict_remove(ctx, subvalue->prefixes[u].prefix);
diff --git a/src/plugins_types.h b/src/plugins_types.h
index 1c4fcee..4df1d94 100644
--- a/src/plugins_types.h
+++ b/src/plugins_types.h
@@ -114,7 +114,9 @@
                                             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,
-                                            other options should be the same as for the first call. */
+                                            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. */
 
 /** @} plugintypeopts */
 
diff --git a/src/tree_data.h b/src/tree_data.h
index 589a3e0..6820144 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -262,7 +262,8 @@
                                           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 */
+    const struct lysc_node *schema;  /**< pointer to the schema definition of this node, note that the target can be not just
+                                          ::struct lysc_node but ::struct lysc_action or ::struct lysc_notif as well */
     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
diff --git a/src/tree_schema.h b/src/tree_schema.h
index dc523cb..f8a2ab6 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -700,45 +700,41 @@
  *     2 - choice       7 - case              12 - extension
  *     3 - leaf         8 - notification      13 - bitenum
  *     4 - leaflist     9 - rpc/action        14 - when
- *     5 - list        10 - feature           15 - must
+ *     5 - list        10 - feature
  *
- *                                             1 1 1 1 1 1
- *     bit name              1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
- *     ---------------------+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *       1 LYS_CONFIG_W     |x|x|x|x|x|x|x| | | | | | | | |
- *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *       2 LYS_CONFIG_R     |x|x|x|x|x|x|x| | | | | | | | |
- *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *       3 LYS_STATUS_CURR  |x|x|x|x|x|x|x|x|x|x|x|x| | | |
- *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *       4 LYS_STATUS_DEPRC |x|x|x|x|x|x|x|x|x|x|x|x| | | |
- *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *       5 LYS_STATUS_OBSLT |x|x|x|x|x|x|x|x|x|x|x|x| | | |
- *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *       6 LYS_MAND_TRUE    |x|x|x|x|x|x| | | | | | | | | |
- *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *       7 LYS_ORDBY_USER   | | | |x|x| | | | | | | | | | |
- *         LYS_MAND_FALSE   | |x|x| | |x| | | | | | | | | |
- *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *       8 LYS_ORDBY_SYSTEM | | | |x|x| | | | | | | | | | |
- *         LYS_PRESENCE     |x| | | | | | | | | | | | | | |
- *         LYS_UNIQUE       | | |x| | | | | | | | | | | | |
- *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *       9 LYS_KEY          | | |x| | | | | | | | | | | | |
- *         LYS_FENABLED     | | | | | | | | | |x| | | | | |
- *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *      10 LYS_SET_DFLT     | | |x|x| | |x| | | | | | | | |
- *         LYS_ISENUM       | | | | | | | | | | | | |x| | |
- *         LYS_KEYLESS      | | | | |x| | | | | | | | | | |
- *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *      11 LYS_SET_UNITS    | | |x|x| | | | | | | | | | | |
- *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *      12 LYS_SET_CONFIG   |x|x|x|x|x|x| | | | | | | | | |
- *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *      13 LYS_XPATH_DEP    |x|x|x|x|x|x|x|x| | | | | |x|x|
- *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *      14 LYS_LEAFREF_DEP  | | |x|x| | | | | | | | | | | |
- *     ---------------------+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *                                             1 1 1 1 1
+ *     bit name              1 2 3 4 5 6 7 8 9 0 1 2 3 4
+ *     ---------------------+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *       1 LYS_CONFIG_W     |x|x|x|x|x|x|x| | | | | | | |
+ *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *       2 LYS_CONFIG_R     |x|x|x|x|x|x|x| | | | | | | |
+ *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *       3 LYS_STATUS_CURR  |x|x|x|x|x|x|x|x|x|x|x|x| |x|
+ *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *       4 LYS_STATUS_DEPRC |x|x|x|x|x|x|x|x|x|x|x|x| |x|
+ *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *       5 LYS_STATUS_OBSLT |x|x|x|x|x|x|x|x|x|x|x|x| |x|
+ *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *       6 LYS_MAND_TRUE    |x|x|x|x|x|x| | | | | | | | |
+ *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *       7 LYS_ORDBY_USER   | | | |x|x| | | | | | | | | |
+ *         LYS_MAND_FALSE   | |x|x| | |x| | | | | | | | |
+ *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *       8 LYS_ORDBY_SYSTEM | | | |x|x| | | | | | | | | |
+ *         LYS_PRESENCE     |x| | | | | | | | | | | | | |
+ *         LYS_UNIQUE       | | |x| | | | | | | | | | | |
+ *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *       9 LYS_KEY          | | |x| | | | | | | | | | | |
+ *         LYS_FENABLED     | | | | | | | | | |x| | | | |
+ *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *      10 LYS_SET_DFLT     | | |x|x| | |x| | | | | | | |
+ *         LYS_ISENUM       | | | | | | | | | | | | |x| |
+ *         LYS_KEYLESS      | | | | |x| | | | | | | | | |
+ *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *      11 LYS_SET_UNITS    | | |x|x| | | | | | | | | | |
+ *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *      12 LYS_SET_CONFIG   |x|x|x|x|x|x| | | | | | | | |
+ *     ---------------------+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  *
  */
 
@@ -800,9 +796,6 @@
 #define LYS_SET_UNITS    0x0400      /**< flag to know if the leaf's/leaflist's units are their own (flag set) or it is taken from the type. */
 #define LYS_SET_CONFIG   0x0800      /**< flag to know if the config property was set explicitly (flag set) or it is inherited. */
 
-#define LYS_XPATH_DEP    0x1000      /**< flag for nodes with when/must with external data dependency. */
-#define LYS_LEAFREF_DEP  0x2000      /**< flag for leaves(-lists) with leafref with external dependency. */
-
 #define LYS_SINGLEQUOTED 0x100       /**< flag for single-quoted argument of an extension instance's substatement, only when the source is YANG */
 #define LYS_DOUBLEQUOTED 0x200       /**< flag for double-quoted argument of an extension instance's substatement, only when the source is YANG */
 
@@ -1170,7 +1163,7 @@
     const char *ref;                 /**< reference */
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
     uint32_t refcount;               /**< reference counter since some of the when statements are shared among several nodes */
-    uint16_t flags;                  /**< [schema node flags](@ref snodeflags) - only LYS_XPATH_DEP and LYS_STATUS are allowed */
+    uint16_t flags;                  /**< [schema node flags](@ref snodeflags) - only LYS_STATUS is allowed */
 };
 
 /**
@@ -1262,7 +1255,6 @@
     const char *emsg;                /**< error-message */
     const char *eapptag;             /**< error-app-tag value */
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
-    uint16_t flags;                  /**< [schema node flags](@ref snodeflags) - only LYS_XPATH_DEP is allowed */
 };
 
 struct lysc_type {
diff --git a/src/tree_schema_compile.c b/src/tree_schema_compile.c
index 59ab14d..574a49e 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -2644,52 +2644,6 @@
 }
 
 /**
- * @brief Check whether a leafref has an external dependency or not.
- *
- * @param[in] startnode Node with the leafref.
- * @param[in] local_mod Local module for the leafref path.
- * @param[in] first_node First found node when resolving the leafref.
- * @param[in] abs_path Whether the leafref path is absolute or relative.
- * @return 0 is the leafref does not require an external dependency, non-zero is it requires.
- */
-static int
-lys_compile_leafref_has_dep_flag(const struct lysc_node *startnode, const struct lys_module *local_mod,
-                                 const struct lysc_node *first_node, int abs_path)
-{
-    const struct lysc_node *op_node, *node;
-
-    /* find operation schema we are in */
-    for (op_node = startnode->parent;
-        op_node && !(op_node->nodetype & (LYS_ACTION | LYS_NOTIF));
-        op_node = op_node->parent);
-
-    if (!op_node) {
-        /* leafref pointing to a different module */
-        if (local_mod != first_node->module) {
-            return 1;
-        }
-    } else if (op_node->parent) {
-        /* inner operation (notif/action) */
-        if (abs_path) {
-            return 1;
-        } else {
-            /* if first_node parent is not op_node, it is external */
-            for (node = first_node; node && (node != op_node); node = node->parent);
-            if (!node) {
-                return 1;
-            }
-        }
-    } else {
-        /* top-level operation (notif/rpc) */
-        if (op_node != first_node) {
-            return 1;
-        }
-    }
-
-    return 0;
-}
-
-/**
  * @brief Validate the leafref path.
  * @param[in] ctx Compile context
  * @param[in] startnode Path context node (where the leafref path begins/is placed).
@@ -2701,7 +2655,7 @@
 lys_compile_leafref_validate(struct lysc_ctx *ctx, struct lysc_node *startnode, struct lysc_type_leafref *leafref,
                              const struct lysc_node **target)
 {
-    const struct lysc_node *node = NULL, *parent = NULL, *tmp_parent;
+    const struct lysc_node *node = NULL, *parent = NULL;
     const struct lys_module *mod;
     struct lysc_type *type;
     const char *id, *prefix, *name;
@@ -2758,16 +2712,6 @@
         }
         parent = node;
 
-        if (!iter) {
-            /* find module whose data will actually contain this leafref */
-            for (tmp_parent = parent; tmp_parent->parent; tmp_parent = tmp_parent->parent);
-
-            /* set external dependency flag, we can decide based on the first found node */
-            if (lys_compile_leafref_has_dep_flag(startnode, tmp_parent->module, node, (parent_times == -1 ? 1 : 0))) {
-                startnode->flags |= LYS_LEAFREF_DEP;
-            }
-        }
-
         if (has_predicate) {
             /* we have predicate, so the current result must be list */
             if (node->nodetype != LYS_LIST) {
@@ -6990,6 +6934,97 @@
 }
 
 /**
+ * @brief Check when for cyclic dependencies.
+ * @param[in] set Set with all the referenced nodes.
+ * @param[in] node Node whose "when" referenced nodes are in @p set.
+ * @return LY_ERR value
+ */
+static LY_ERR
+lys_compile_check_cyclic_when(struct lyxp_set *set, const struct lysc_node *node)
+{
+    struct lyxp_set tmp_set;
+    struct lyxp_set_scnode *xp_scnode;
+    uint32_t i, j;
+    int idx;
+    struct lysc_when *when;
+    LY_ERR ret = LY_SUCCESS;
+
+    memset(&tmp_set, 0, sizeof tmp_set);
+
+    /* prepare in_ctx of the set */
+    for (i = 0; i < set->used; ++i) {
+        xp_scnode = &set->val.scnodes[i];
+
+        if ((xp_scnode->type == LYXP_NODE_ELEM) && (xp_scnode->scnode == node)) {
+            /* node when was already checked */
+            xp_scnode->in_ctx = 2;
+        } else {
+            /* check node when */
+            xp_scnode->in_ctx = 1;
+        }
+    }
+
+    for (i = 0; i < set->used; ++i) {
+        xp_scnode = &set->val.scnodes[i];
+        if (xp_scnode->in_ctx != 1) {
+            /* already checked */
+            continue;
+        }
+
+        if ((xp_scnode->type != LYXP_NODE_ELEM) || !xp_scnode->scnode->when) {
+            /* no when to check */
+            xp_scnode->in_ctx = 0;
+            continue;
+        }
+
+        node = xp_scnode->scnode;
+        do {
+            LY_ARRAY_FOR(node->when, i) {
+                when = node->when[i];
+                ret = lyxp_atomize(when->cond, LYD_UNKNOWN, when->module, when->context,
+                                when->context ? LYXP_NODE_ELEM : LYXP_NODE_ROOT_CONFIG, &tmp_set, LYXP_SCNODE_SCHEMA);
+                if (ret != LY_SUCCESS) {
+                    LOGVAL(set->ctx, LY_VLOG_LYS, node, LYVE_SEMANTICS, "Invalid when condition \"%s\".", when->cond->expr);
+                    goto cleanup;
+                }
+
+                for (j = 0; j < tmp_set.used; ++j) {
+                    /* skip roots'n'stuff */
+                    if (tmp_set.val.scnodes[j].type == LYXP_NODE_ELEM) {
+                        /* try to find this node in our set */
+                        idx = lyxp_set_scnode_dup_node_check(set, tmp_set.val.scnodes[j].scnode, LYXP_NODE_ELEM, -1);
+                        if ((idx > -1) && (set->val.scnodes[idx].in_ctx == 2)) {
+                            LOGVAL(set->ctx, LY_VLOG_LYS, node, LY_VCODE_CIRC_WHEN, node->name, set->val.scnodes[idx].scnode->name);
+                            ret = LY_EVALID;
+                            goto cleanup;
+                        }
+
+                        /* needs to be checked, if in both sets, will be ignored */
+                        tmp_set.val.scnodes[j].in_ctx = 1;
+                    } else {
+                        /* no when, nothing to check */
+                        tmp_set.val.scnodes[j].in_ctx = 0;
+                    }
+                }
+
+                /* merge this set into the global when set */
+                lyxp_set_scnode_merge(set, &tmp_set);
+            }
+
+            /* check when of non-data parents as well */
+            node = node->parent;
+        } while (node && (node->nodetype & (LYS_CASE | LYS_CHOICE)));
+
+        /* this node when was checked */
+        xp_scnode->in_ctx = 2;
+    }
+
+cleanup:
+    lyxp_set_cast(&tmp_set, LYXP_SET_EMPTY);
+    return ret;
+}
+
+/**
  * @brief Check when/must expressions of a node on a compiled schema tree.
  * @param[in] ctx Compile context.
  * @param[in] node Node to check.
@@ -6998,7 +7033,6 @@
 static LY_ERR
 lys_compile_check_xpath(struct lysc_ctx *ctx, const struct lysc_node *node)
 {
-    struct lysc_node *parent, *elem;
     struct lyxp_set tmp_set;
     uint32_t i, j;
     int opts, input_done = 0;
@@ -7049,15 +7083,8 @@
         break;
     }
 
-    /* find operation if in one, used later */
-    for (parent = (struct lysc_node *)node;
-         parent && !(parent->nodetype & (LYS_ACTION | LYS_NOTIF));
-         parent = parent->parent);
-
-
     /* check "when" */
     LY_ARRAY_FOR(when, i) {
-        lyxp_set_cast(&tmp_set, LYXP_SET_EMPTY);
         ret = lyxp_atomize(when[i]->cond, LYD_UNKNOWN, when[i]->module, when[i]->context,
                            when[i]->context ? LYXP_NODE_ELEM : LYXP_NODE_ROOT_CONFIG, &tmp_set, opts);
         if (ret != LY_SUCCESS) {
@@ -7068,31 +7095,30 @@
         ctx->path[0] = '\0';
         lysc_path((struct lysc_node *)node, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
         for (j = 0; j < tmp_set.used; ++j) {
-            /* skip roots'n'stuff */
+            /* skip roots'n'stuff, set in_ctx for when checking */
             if (tmp_set.val.scnodes[j].type == LYXP_NODE_ELEM) {
-                /* XPath expression cannot reference "lower" status than the node that has the definition */
-                ret = lysc_check_status(ctx, when[i]->flags, when[i]->module, node->name, tmp_set.val.scnodes[j].scnode->flags,
-                                        tmp_set.val.scnodes[j].scnode->module, tmp_set.val.scnodes[j].scnode->name);
-                LY_CHECK_GOTO(ret, cleanup);
+                struct lysc_node *schema = tmp_set.val.scnodes[j].scnode;
 
-                if (parent) {
-                    for (elem = tmp_set.val.scnodes[j].scnode; elem && (elem != parent); elem = elem->parent);
-                    if (!elem) {
-                        /* not in node's RPC or notification subtree, set the correct dep flag */
-                        when[i]->flags |= LYS_XPATH_DEP;
-                        ((struct lysc_node *)node)->flags |= LYS_XPATH_DEP;
-                    }
-                }
+                /* XPath expression cannot reference "lower" status than the node that has the definition */
+                ret = lysc_check_status(ctx, when[i]->flags, when[i]->module, node->name, schema->flags, schema->module,
+                                        schema->name);
+                LY_CHECK_GOTO(ret, cleanup);
             }
         }
 
+        /* check dummy node accessing */
+        /* TODO */
+
+        /* check cyclic dependencies */
+        ret = lys_compile_check_cyclic_when(&tmp_set, node);
+        LY_CHECK_GOTO(ret, cleanup);
+
         lyxp_set_cast(&tmp_set, LYXP_SET_EMPTY);
     }
 
 check_musts:
     /* check "must" */
     LY_ARRAY_FOR(musts, i) {
-        lyxp_set_cast(&tmp_set, LYXP_SET_EMPTY);
         ret = lyxp_atomize(musts[i].cond, LYD_UNKNOWN, musts[i].module, node, LYXP_NODE_ELEM, &tmp_set, opts);
         if (ret != LY_SUCCESS) {
             LOGVAL(ctx->ctx, LY_VLOG_LYS, node, LYVE_SEMANTICS, "Invalid must restriction \"%s\".", musts[i].cond->expr);
@@ -7108,15 +7134,6 @@
                 ret = lysc_check_status(ctx, node->flags, musts[i].module, node->name, tmp_set.val.scnodes[j].scnode->flags,
                                         tmp_set.val.scnodes[j].scnode->module, tmp_set.val.scnodes[j].scnode->name);
                 LY_CHECK_GOTO(ret, cleanup);
-
-                if (parent) {
-                    for (elem = tmp_set.val.scnodes[j].scnode; elem && (elem != parent); elem = elem->parent);
-                    if (!elem) {
-                        /* not in node's RPC or notification subtree, set the correct dep flag */
-                        musts[i].flags |= LYS_XPATH_DEP;
-                        ((struct lysc_node *)node)->flags |= LYS_XPATH_DEP;
-                    }
-                }
             }
         }
 
diff --git a/src/xpath.c b/src/xpath.c
index 4505141..995941c 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -35,7 +35,6 @@
 #include "plugins_types.h"
 
 static LY_ERR reparse_or_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx);
-static int set_scnode_insert_node(struct lyxp_set *set, const struct lysc_node *node, enum lyxp_node_type node_type);
 static LY_ERR eval_expr_select(struct lyxp_expr *exp, uint16_t *exp_idx, enum lyxp_expr_type etype, struct lyxp_set *set, int options);
 
 /**
@@ -775,7 +774,7 @@
 
         for (i = 0; i < set->used; ++i) {
             if (set->val.scnodes[i].in_ctx == 1) {
-                if (set_scnode_insert_node(ret, set->val.scnodes[i].scnode, set->val.scnodes[i].type)) {
+                if (lyxp_set_scnode_insert_node(ret, set->val.scnodes[i].scnode, set->val.scnodes[i].type)) {
                     lyxp_set_free(ret);
                     return NULL;
                 }
@@ -1050,17 +1049,8 @@
     return LY_SUCCESS;
 }
 
-/**
- * @brief Check for duplicates in a schema node set.
- *
- * @param[in] set Set to check.
- * @param[in] node Node to look for in @p set.
- * @param[in] node_type Type of @p node.
- * @param[in] skip_idx Index from @p set to skip.
- * @return Index of the found node, -1 if not found.
- */
-static int
-set_scnode_dup_node_check(struct lyxp_set *set, const struct lysc_node *node, enum lyxp_node_type node_type, int skip_idx)
+int
+lyxp_set_scnode_dup_node_check(struct lyxp_set *set, const struct lysc_node *node, enum lyxp_node_type node_type, int skip_idx)
 {
     uint32_t i;
 
@@ -1077,14 +1067,8 @@
     return -1;
 }
 
-/**
- * @brief Merge 2 schema node sets.
- *
- * @param[in] set1 Set to merge into.
- * @param[in] set2 Set to merge. Its content is freed.
- */
-static void
-set_scnode_merge(struct lyxp_set *set1, struct lyxp_set *set2)
+void
+lyxp_set_scnode_merge(struct lyxp_set *set1, struct lyxp_set *set2)
 {
     uint32_t orig_used, i, j;
 
@@ -1185,22 +1169,14 @@
     set_insert_node_hash(set, (struct lyd_node *)node, node_type);
 }
 
-/**
- * @brief Insert schema node into set.
- *
- * @param[in] set Set to insert into.
- * @param[in] node Node to insert.
- * @param[in] node_type Node type of @p node.
- * @return Index of the inserted node in set.
- */
-static int
-set_scnode_insert_node(struct lyxp_set *set, const struct lysc_node *node, enum lyxp_node_type node_type)
+int
+lyxp_set_scnode_insert_node(struct lyxp_set *set, const struct lysc_node *node, enum lyxp_node_type node_type)
 {
     int ret;
 
     assert(set->type == LYXP_SET_SCNODE_SET);
 
-    ret = set_scnode_dup_node_check(set, node, node_type, -1);
+    ret = lyxp_set_scnode_dup_node_check(set, node, node_type, -1);
     if (ret > -1) {
         set->val.scnodes[ret].in_ctx = 1;
     } else {
@@ -3503,7 +3479,7 @@
     if (options & LYXP_SCNODE_ALL) {
         set_scnode_clear_ctx(set);
 
-        set_scnode_insert_node(set, set->ctx_scnode, LYXP_NODE_ELEM);
+        lyxp_set_scnode_insert_node(set, set->ctx_scnode, LYXP_NODE_ELEM);
     } else {
         lyxp_set_cast(set, LYXP_SET_EMPTY);
 
@@ -3555,7 +3531,7 @@
             rc = lys_compile_leafref_validate(&cctx, (struct lysc_node *)sleaf, (struct lysc_type_leafref *)sleaf->type, &target);
             /* it was already validated, it must succeed */
             if (rc == LY_SUCCESS) {
-                set_scnode_insert_node(set, target, LYXP_NODE_ELEM);
+                lyxp_set_scnode_insert_node(set, target, LYXP_NODE_ELEM);
             }
         }
 
@@ -5276,7 +5252,7 @@
 
     if (options & LYXP_SCNODE_ALL) {
         set_scnode_clear_ctx(set);
-        set_scnode_insert_node(set, NULL, set->root_type);
+        lyxp_set_scnode_insert_node(set, NULL, set->root_type);
     } else {
         lyxp_set_cast(set, LYXP_SET_EMPTY);
         set_insert_node(set, NULL, 0, set->root_type, 0);
@@ -5502,7 +5478,7 @@
                 sub = NULL;
                 while ((sub = lys_getnext(sub, NULL, moveto_mod->compiled, getnext_opts))) {
                     if (!moveto_scnode_check(sub, set->root_type, name_dict, moveto_mod)) {
-                        idx = set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
+                        idx = lyxp_set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
                         /* we need to prevent these nodes from being considered in this moveto */
                         if ((idx < orig_used) && (idx > i)) {
                             set->val.scnodes[idx].in_ctx = 2;
@@ -5524,7 +5500,7 @@
             sub = NULL;
             while ((sub = lys_getnext(sub, start_parent, NULL, getnext_opts))) {
                 if (!moveto_scnode_check(sub, set->root_type, name_dict, (moveto_mod ? moveto_mod : set->local_mod))) {
-                    idx = set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
+                    idx = lyxp_set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
                     if ((idx < orig_used) && (idx > i)) {
                         set->val.scnodes[idx].in_ctx = 2;
                         temp_ctx = 1;
@@ -5695,14 +5671,14 @@
 
             rc = moveto_scnode_check(elem, set->root_type, qname, moveto_mod);
             if (!rc) {
-                if ((idx = set_scnode_dup_node_check(set, elem, LYXP_NODE_ELEM, i)) > -1) {
+                if ((idx = lyxp_set_scnode_dup_node_check(set, elem, LYXP_NODE_ELEM, i)) > -1) {
                     set->val.scnodes[idx].in_ctx = 1;
                     if (idx > i) {
                         /* we will process it later in the set */
                         goto skip_children;
                     }
                 } else {
-                    set_scnode_insert_node(set, elem, LYXP_NODE_ELEM);
+                    lyxp_set_scnode_insert_node(set, elem, LYXP_NODE_ELEM);
                 }
             } else if (rc == LY_EINVAL) {
                 goto skip_children;
@@ -6142,7 +6118,7 @@
                     continue;
                 }
 
-                set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
+                lyxp_set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
                 /* throw away the insert index, we want to consider that node again, recursively */
             }
         }
@@ -6287,7 +6263,7 @@
             new_type = LYXP_NODE_ELEM;
         }
 
-        idx = set_scnode_insert_node(set, new_node, new_type);
+        idx = lyxp_set_scnode_insert_node(set, new_node, new_type);
         if ((idx < orig_used) && (idx > i)) {
             set->val.scnodes[idx].in_ctx = 2;
             temp_ctx = 1;
@@ -7212,7 +7188,7 @@
             /* merge all nodes from arg evaluations */
             for (i = 0; i < arg_count; ++i) {
                 set_scnode_clear_ctx(args[i]);
-                set_scnode_merge(set, args[i]);
+                lyxp_set_scnode_merge(set, args[i]);
             }
         }
     } else {
@@ -7452,7 +7428,7 @@
 
         /* eval */
         if (options & LYXP_SCNODE_ALL) {
-            set_scnode_merge(set, &set2);
+            lyxp_set_scnode_merge(set, &set2);
         } else {
             rc = moveto_union(set, &set2);
             LY_CHECK_GOTO(rc, cleanup);
@@ -7565,7 +7541,7 @@
         /* eval */
         if (options & LYXP_SCNODE_ALL) {
             warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
-            set_scnode_merge(set, &set2);
+            lyxp_set_scnode_merge(set, &set2);
             set_scnode_clear_ctx(set);
         } else {
             rc = moveto_op_math(set, &set2, &exp->expr[exp->tok_pos[this_op]]);
@@ -7633,7 +7609,7 @@
         /* eval */
         if (options & LYXP_SCNODE_ALL) {
             warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
-            set_scnode_merge(set, &set2);
+            lyxp_set_scnode_merge(set, &set2);
             set_scnode_clear_ctx(set);
         } else {
             rc = moveto_op_math(set, &set2, &exp->expr[exp->tok_pos[this_op]]);
@@ -7703,7 +7679,7 @@
         /* eval */
         if (options & LYXP_SCNODE_ALL) {
             warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
-            set_scnode_merge(set, &set2);
+            lyxp_set_scnode_merge(set, &set2);
             set_scnode_clear_ctx(set);
         } else {
             rc = moveto_op_comp(set, &set2, &exp->expr[exp->tok_pos[this_op]], options);
@@ -7772,7 +7748,7 @@
             warn_operands(set->ctx, set, &set2, 0, exp->expr, exp->tok_pos[this_op - 1]);
             warn_equality_value(exp, set, *exp_idx - 1, this_op - 1, *exp_idx - 1);
             warn_equality_value(exp, &set2, this_op - 1, this_op - 1, *exp_idx - 1);
-            set_scnode_merge(set, &set2);
+            lyxp_set_scnode_merge(set, &set2);
             set_scnode_clear_ctx(set);
         } else {
             /* special handling of evaluations of identityref comparisons, always compare prefixed identites */
@@ -7860,7 +7836,7 @@
         /* eval - just get boolean value actually */
         if (set->type == LYXP_SET_SCNODE_SET) {
             set_scnode_clear_ctx(&set2);
-            set_scnode_merge(set, &set2);
+            lyxp_set_scnode_merge(set, &set2);
         } else {
             lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
             set_fill_set(set, &set2);
@@ -7932,7 +7908,7 @@
         /* eval - just get boolean value actually */
         if (set->type == LYXP_SET_SCNODE_SET) {
             set_scnode_clear_ctx(&set2);
-            set_scnode_merge(set, &set2);
+            lyxp_set_scnode_merge(set, &set2);
         } else {
             lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
             set_fill_set(set, &set2);
@@ -8047,29 +8023,20 @@
 }
 
 LY_ERR
-lyxp_eval(const char *expr, LYD_FORMAT format, const struct lys_module *local_mod, const struct lyd_node *ctx_node,
+lyxp_eval(struct lyxp_expr *exp, LYD_FORMAT format, const struct lys_module *local_mod, const struct lyd_node *ctx_node,
           enum lyxp_node_type ctx_node_type, const struct lyd_node **trees, struct lyxp_set *set, int options)
 {
-    struct ly_ctx *ctx;
-    struct lyxp_expr *exp;
     uint16_t exp_idx = 0;
     LY_ERR rc;
 
-    LY_CHECK_ARG_RET(NULL, expr, local_mod, set, LY_EINVAL);
-
-    ctx = local_mod->ctx;
-
-    exp = lyxp_expr_parse(ctx, expr);
-    if (!exp) {
-        return LY_EINVAL;
-    }
+    LY_CHECK_ARG_RET(NULL, exp, local_mod, set, LY_EINVAL);
 
     /* prepare set for evaluation */
     exp_idx = 0;
     memset(set, 0, sizeof *set);
     set->type = LYXP_SET_EMPTY;
     set_insert_node(set, (struct lyd_node *)ctx_node, 0, ctx_node_type, options);
-    set->ctx = ctx;
+    set->ctx = local_mod->ctx;
     set->ctx_node = ctx_node;
     set->root_type = lyxp_get_root_type(ctx_node, NULL, options);
     set->local_mod = local_mod;
@@ -8082,7 +8049,6 @@
         lyxp_set_cast(set, LYXP_SET_EMPTY);
     }
 
-    lyxp_expr_free(ctx, exp);
     return rc;
 }
 
@@ -8340,7 +8306,7 @@
     exp_idx = 0;
     memset(set, 0, sizeof *set);
     set->type = LYXP_SET_SCNODE_SET;
-    set_scnode_insert_node(set, ctx_scnode, ctx_scnode_type);
+    lyxp_set_scnode_insert_node(set, ctx_scnode, ctx_scnode_type);
     set->ctx = ctx;
     set->ctx_scnode = ctx_scnode;
     set->root_type = lyxp_get_root_type(NULL, ctx_scnode, options);
diff --git a/src/xpath.h b/src/xpath.h
index 527153c..1e27ab1 100644
--- a/src/xpath.h
+++ b/src/xpath.h
@@ -255,7 +255,7 @@
  * @brief Evaluate an XPath expression on data. Be careful when using this function, the result can often
  * be confusing without thorough understanding of XPath evaluation rules defined in RFC 7950.
  *
- * @param[in] expr XPath expression to evaluate.
+ * @param[in] exp Parsed XPath expression to be evaluated.
  * @param[in] format Format of the XPath expression (more specifcally, of any used prefixes).
  * @param[in] local_mod Local module relative to the @p expr.
  * @param[in] ctx_node Current (context) data node, NULL for root node.
@@ -271,9 +271,10 @@
  * the @p set to empty (if allocated statically) or free it (if allocated dynamically) to
  * prevent memory leaks.
  * @param[in] options Whether to apply some evaluation restrictions.
- * @return LY_ERR
+ * @return LY_ERR (LY_EINVAL, LY_EMEM, LY_EINT, LY_EVALID for invalid argument types/count,
+ * LY_EINCOMPLETE for unresolved when).
  */
-LY_ERR lyxp_eval(const char *expr, LYD_FORMAT format, const struct lys_module *local_mod, const struct lyd_node *ctx_node,
+LY_ERR lyxp_eval(struct lyxp_expr *exp, LYD_FORMAT format, const struct lys_module *local_mod, const struct lyd_node *ctx_node,
                  enum lyxp_node_type ctx_node_type, const struct lyd_node **trees, struct lyxp_set *set, int options);
 
 #define LYXP_SCHEMA 0x01 /**< Apply data node access restrictions defined for 'when' and 'must' evaluation. */
@@ -294,7 +295,7 @@
  * the @p set to empty (if allocated statically) or free it (if allocated dynamically) to
  * prevent memory leaks.
  * @param[in] options Whether to apply some evaluation restrictions, one flag must always be used.
- * @return LY_ERR
+ * @return LY_ERR (same as lyxp_eval()).
  */
 LY_ERR lyxp_atomize(struct lyxp_expr *exp, LYD_FORMAT format, const struct lys_module *local_mod, const struct lysc_node *ctx_scnode,
                     enum lyxp_node_type ctx_scnode_type, struct lyxp_set *set, int options);
@@ -317,6 +318,36 @@
 LY_ERR lyxp_set_cast(struct lyxp_set *set, enum lyxp_set_type target);
 
 /**
+ * @brief Insert schema node into set.
+ *
+ * @param[in] set Set to insert into.
+ * @param[in] node Node to insert.
+ * @param[in] node_type Node type of @p node.
+ * @return Index of the inserted node in set.
+ */
+int lyxp_set_scnode_insert_node(struct lyxp_set *set, const struct lysc_node *node, enum lyxp_node_type node_type);
+
+/**
+ * @brief Check for duplicates in a schema node set.
+ *
+ * @param[in] set Set to check.
+ * @param[in] node Node to look for in @p set.
+ * @param[in] node_type Type of @p node.
+ * @param[in] skip_idx Index from @p set to skip.
+ * @return Index of the found node, -1 if not found.
+ */
+int lyxp_set_scnode_dup_node_check(struct lyxp_set *set, const struct lysc_node *node, enum lyxp_node_type node_type,
+                                   int skip_idx);
+
+/**
+ * @brief Merge 2 schema node sets.
+ *
+ * @param[in] set1 Set to merge into.
+ * @param[in] set2 Set to merge. Its content is freed.
+ */
+void lyxp_set_scnode_merge(struct lyxp_set *set1, struct lyxp_set *set2);
+
+/**
  * @brief Parse an XPath expression into a structure of tokens.
  *        Logs directly.
  *
diff --git a/tests/src/test_tree_schema_compile.c b/tests/src/test_tree_schema_compile.c
index 20ef15b..de53e76 100644
--- a/tests/src/test_tree_schema_compile.c
+++ b/tests/src/test_tree_schema_compile.c
@@ -877,12 +877,10 @@
     assert_non_null(rpc);
     assert_int_equal(1, LY_ARRAY_SIZE(rpc));
     assert_int_equal(LYS_ACTION, rpc->nodetype);
-    assert_int_equal(LYS_STATUS_CURR | LYS_XPATH_DEP, rpc->flags);
+    assert_int_equal(LYS_STATUS_CURR, rpc->flags);
     assert_string_equal("b", rpc->name);
     assert_null(rpc->input.musts);
     assert_int_equal(2, LY_ARRAY_SIZE(rpc->output.musts));
-    assert_int_equal(0, rpc->output.musts[0].flags);
-    assert_int_equal(LYS_XPATH_DEP, rpc->output.musts[1].flags);
 
     /* invalid */
     assert_null(lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa;container top {action x;}}", LYS_IN_YANG));
@@ -951,11 +949,10 @@
     assert_non_null(notif->data);
     assert_string_equal("x", notif->data->name);
     assert_int_equal(LYS_NOTIF, notif[1].nodetype);
-    assert_int_equal(LYS_STATUS_CURR | LYS_XPATH_DEP, notif[1].flags);
+    assert_int_equal(LYS_STATUS_CURR, notif[1].flags);
     assert_string_equal("b2", notif[1].name);
     assert_null(notif[1].data);
     assert_int_equal(1, LY_ARRAY_SIZE(notif[1].musts));
-    assert_int_equal(LYS_XPATH_DEP, notif[1].musts[0].flags);
 
     /* invalid */
     assert_null(lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa;container top {notification x;}}", LYS_IN_YANG));
@@ -3429,6 +3426,75 @@
     ly_ctx_destroy(ctx, NULL);
 }
 
+static void
+test_when(void **state)
+{
+    *state = test_when;
+
+    struct ly_ctx *ctx;
+
+    assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIRS, &ctx));
+
+    assert_null(lys_parse_mem(ctx,
+        "module a {"
+            "namespace urn:a;"
+            "prefix a;"
+            "container cont {"
+                "leaf l {"
+                    "when \"/cont/lst[val='25']\";"
+                    "type empty;"
+                "}"
+                "list lst {"
+                    "key \"k\";"
+                    "leaf k {"
+                        "type uint8;"
+                    "}"
+                    "leaf val {"
+                        "when /cont2;"
+                        "type int32;"
+                    "}"
+                "}"
+            "}"
+            "container cont2 {"
+                "presence \"a\";"
+                "when ../cont/l;"
+            "}"
+        "}"
+    , LYS_IN_YANG));
+    logbuf_assert("When condition of \"cont2\" includes a self-reference (referenced by when of \"l\").");
+
+    assert_null(lys_parse_mem(ctx,
+        "module a {"
+            "namespace urn:a;"
+            "prefix a;"
+            "container cont {"
+                "leaf l {"
+                    "when \"/cont/lst[val='25']\";"
+                    "type empty;"
+                "}"
+                "list lst {"
+                    "key \"k\";"
+                    "leaf k {"
+                        "type uint8;"
+                    "}"
+                    "leaf val {"
+                        "when /cont2;"
+                        "type int32;"
+                    "}"
+                "}"
+            "}"
+            "container cont2 {"
+                "presence \"a\";"
+                "when ../cont/lst/val;"
+            "}"
+        "}"
+    , LYS_IN_YANG));
+    logbuf_assert("When condition of \"cont2\" includes a self-reference (referenced by when of \"val\").");
+
+    *state = NULL;
+    ly_ctx_destroy(ctx, NULL);
+}
+
 int main(void)
 {
     const struct CMUnitTest tests[] = {
@@ -3460,6 +3526,7 @@
         cmocka_unit_test_setup_teardown(test_refine, logger_setup, logger_teardown),
         cmocka_unit_test_setup_teardown(test_augment, logger_setup, logger_teardown),
         cmocka_unit_test_setup_teardown(test_deviation, logger_setup, logger_teardown),
+        cmocka_unit_test_setup_teardown(test_when, logger_setup, logger_teardown),
     };
 
     return cmocka_run_group_tests(tests, NULL, NULL);