diff --git a/entities.c b/entities.c
index 43549bc5..e4a09d62 100644
--- a/entities.c
+++ b/entities.c
@@ -164,6 +164,7 @@ xmlCreateEntity(xmlDictPtr dict, const xmlChar *name, int type,
     memset(ret, 0, sizeof(xmlEntity));
     ret->type = XML_ENTITY_DECL;
     ret->checked = 0;
+    ret->guard = XML_ENTITY_NOT_BEING_CHECKED;
 
     /*
      * fill the structure.
@@ -936,6 +937,7 @@ xmlCopyEntity(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
 	cur->orig = xmlStrdup(ent->orig);
     if (ent->URI != NULL)
 	cur->URI = xmlStrdup(ent->URI);
+    cur->guard = 0;
     return(cur);
 }
 
diff --git a/include/libxml/entities.h b/include/libxml/entities.h
index 47b4573e..012efab2 100644
--- a/include/libxml/entities.h
+++ b/include/libxml/entities.h
@@ -35,8 +35,13 @@ typedef enum {
  * and the linkind data needed for the linking in the hash table.
  */
 
+typedef enum {
+  XML_ENTITY_NOT_BEING_CHECKED,
+  XML_ENTITY_BEING_CHECKED              /* entity check is in progress */
+} xmlEntityRecursionGuard;
+
 struct _xmlEntity {
-    void           *_private;	        /* application data */
+    void               *_private;	/* application data */
     xmlElementType          type;       /* XML_ENTITY_DECL, must be second ! */
     const xmlChar          *name;	/* Entity name */
     struct _xmlNode    *children;	/* First child link */
@@ -56,10 +61,11 @@ struct _xmlEntity {
     struct _xmlEntity     *nexte;	/* unused */
     const xmlChar           *URI;	/* the full URI as computed */
     int                    owner;	/* does the entity own the childrens */
-    int			 checked;	/* was the entity content checked */
-					/* this is also used to count entities
-					 * references done from that entity
-					 * and if it contains '<' */
+    int                  checked;	/* was the entity content checked and */
+					/* l.o. bit: replacement contains '<' */
+					/* remaining bits: one plus count of */
+                                        /* entity references from this entity */
+    xmlEntityRecursionGuard guard;
 };
 
 /*
diff --git a/parser.c b/parser.c
index ca9fde2c..4264445a 100644
--- a/parser.c
+++ b/parser.c
@@ -143,18 +143,25 @@ xmlParserEntityCheck(xmlParserCtxtPtr ctxt, size_t size,
      * This may look absurd but is needed to detect
      * entities problems
      */
+    if ((ent != NULL) && (ent->guard == XML_ENTITY_BEING_CHECKED)) {
+        xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL);
+        return (1);
+    }
+
     if ((ent != NULL) && (ent->etype != XML_INTERNAL_PREDEFINED_ENTITY) &&
 	(ent->content != NULL) && (ent->checked == 0) &&
 	(ctxt->errNo != XML_ERR_ENTITY_LOOP)) {
 	unsigned long oldnbent = ctxt->nbentities, diff;
 	xmlChar *rep;
 
+        ent->guard = XML_ENTITY_BEING_CHECKED;
 	ent->checked = 1;
 
         ++ctxt->depth;
 	rep = xmlStringDecodeEntities(ctxt, ent->content,
 				  XML_SUBSTITUTE_REF, 0, 0, 0);
         --ctxt->depth;
+        ent->guard = XML_ENTITY_NOT_BEING_CHECKED;
 	if ((rep == NULL) || (ctxt->errNo == XML_ERR_ENTITY_LOOP)) {
 	    ent->content[0] = 0;
 	}
@@ -7116,23 +7123,28 @@ xmlParseReference(xmlParserCtxtPtr ctxt) {
 	 * if its replacement text matches the production labeled
 	 * content.
 	 */
-	if (ent->etype == XML_INTERNAL_GENERAL_ENTITY) {
-	    ctxt->depth++;
-	    ret = xmlParseBalancedChunkMemoryInternal(ctxt, ent->content,
-	                                              user_data, &list);
-	    ctxt->depth--;
-
-	} else if (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY) {
-	    ctxt->depth++;
-	    ret = xmlParseExternalEntityPrivate(ctxt->myDoc, ctxt, ctxt->sax,
-	                                   user_data, ctxt->depth, ent->URI,
-					   ent->ExternalID, &list);
-	    ctxt->depth--;
-	} else {
-	    ret = XML_ERR_ENTITY_PE_INTERNAL;
-	    xmlErrMsgStr(ctxt, XML_ERR_INTERNAL_ERROR,
-			 "invalid entity type found\n", NULL);
-	}
+        if (ent->guard == XML_ENTITY_BEING_CHECKED) {
+            ret = XML_ERR_ENTITY_LOOP;
+        } else {
+            ent->guard = XML_ENTITY_BEING_CHECKED;
+            if (ent->etype == XML_INTERNAL_GENERAL_ENTITY) {
+                ctxt->depth++;
+                ret = xmlParseBalancedChunkMemoryInternal(ctxt, ent->content,
+                                                          user_data, &list);
+                ctxt->depth--;
+            } else if (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY) {
+                ctxt->depth++;
+                ret = xmlParseExternalEntityPrivate(ctxt->myDoc, ctxt, ctxt->sax,
+                                               user_data, ctxt->depth, ent->URI,
+                                               ent->ExternalID, &list);
+                ctxt->depth--;
+            } else {
+                ret = XML_ERR_ENTITY_PE_INTERNAL;
+                xmlErrMsgStr(ctxt, XML_ERR_INTERNAL_ERROR,
+                             "invalid entity type found\n", NULL);
+            }
+            ent->guard = XML_ENTITY_NOT_BEING_CHECKED;
+        }
 
 	/*
 	 * Store the number of entities needing parsing for this entity
@@ -7239,23 +7251,29 @@ xmlParseReference(xmlParserCtxtPtr ctxt) {
 	    else
 		user_data = ctxt->userData;
 
-	    if (ent->etype == XML_INTERNAL_GENERAL_ENTITY) {
-		ctxt->depth++;
-		ret = xmlParseBalancedChunkMemoryInternal(ctxt,
-				   ent->content, user_data, NULL);
-		ctxt->depth--;
-	    } else if (ent->etype ==
-		       XML_EXTERNAL_GENERAL_PARSED_ENTITY) {
-		ctxt->depth++;
-		ret = xmlParseExternalEntityPrivate(ctxt->myDoc, ctxt,
-			   ctxt->sax, user_data, ctxt->depth,
-			   ent->URI, ent->ExternalID, NULL);
-		ctxt->depth--;
-	    } else {
-		ret = XML_ERR_ENTITY_PE_INTERNAL;
-		xmlErrMsgStr(ctxt, XML_ERR_INTERNAL_ERROR,
-			     "invalid entity type found\n", NULL);
-	    }
+            if (ent->guard == XML_ENTITY_BEING_CHECKED) {
+                ret = XML_ERR_ENTITY_LOOP;
+            } else {
+                ent->guard = XML_ENTITY_BEING_CHECKED;
+                if (ent->etype == XML_INTERNAL_GENERAL_ENTITY) {
+                    ctxt->depth++;
+                    ret = xmlParseBalancedChunkMemoryInternal(ctxt,
+                                       ent->content, user_data, NULL);
+                    ctxt->depth--;
+                } else if (ent->etype ==
+                           XML_EXTERNAL_GENERAL_PARSED_ENTITY) {
+                    ctxt->depth++;
+                    ret = xmlParseExternalEntityPrivate(ctxt->myDoc, ctxt,
+                               ctxt->sax, user_data, ctxt->depth,
+                               ent->URI, ent->ExternalID, NULL);
+                    ctxt->depth--;
+                } else {
+                    ret = XML_ERR_ENTITY_PE_INTERNAL;
+                    xmlErrMsgStr(ctxt, XML_ERR_INTERNAL_ERROR,
+                                 "invalid entity type found\n", NULL);
+                }
+                ent->guard = XML_ENTITY_NOT_BEING_CHECKED;
+            }
 	    if (ret == XML_ERR_ENTITY_LOOP) {
 		xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL);
 		return;