diff --git a/scope4j/src/main/jastadd/ProgramToScopeTree.jrag b/scope4j/src/main/jastadd/ProgramToScopeTree.jrag
index 6bd575cb2424d020b5ad12ce170e64eca288d3f6..4695a2fe3e3723a4ecfcc6185be7cbc5e91bea5b 100644
--- a/scope4j/src/main/jastadd/ProgramToScopeTree.jrag
+++ b/scope4j/src/main/jastadd/ProgramToScopeTree.jrag
@@ -9,6 +9,7 @@ aspect ProgramToScopeTree {
 
   /** a relational nta collection attribute to compute a special scope containing visible fields and subtypes */
   coll TypeDeclScope ClassDecl.protectedScope() [asProtectedScope()] with addElement root Program;
+  coll TypeDeclScope ClassDecl.packageScope() [asPackageScope()] with addElement root Program;
 
   // collect all scopes
   TypeDecl contributes scope() when !isClassDecl() to ASTNode.scope() for containingScope();
@@ -17,16 +18,23 @@ aspect ProgramToScopeTree {
       to ASTNode.scope()
       for containingScope();
   ClassDecl contributes protectedScope()
-      when !isInnerClass() && superclass().isClassDecl() && superclass().compilationUnit().fromSource()
+      when !isInnerClass() && superclass().isClassDecl() && superclass().compilationUnit().fromSource() && !accessibleFromPackage(superclass().hostPackage())
       to ClassDecl.protectedScope()
       for superclass();
+  ClassDecl contributes protectedScope()
+      when !isInnerClass() && superclass().isClassDecl() && superclass().compilationUnit().fromSource() && accessibleFromPackage(superclass().hostPackage())
+      to ClassDecl.packageScope()
+      for superclass();
   Block contributes scope() to ASTNode.scope() for containingScope();
   ForStmt contributes scope() when !(getStmt() instanceof Block) to ASTNode.scope() for containingScope();
   EnhancedForStmt contributes scope() when !(getStmt() instanceof Block) to ASTNode.scope() for containingScope();
 
   // collect all elements
   Declarator contributes asDeclaration() when !isField() || isPrivate() to ASTNode.scope() for containingScope();
-  Declarator contributes asDeclaration() when isField() && !isPrivate() to ClassDecl.protectedScope() for containingScope();
+  // field which is neither private, protected, nor public -> package-private scope
+  Declarator contributes asDeclaration() when isField() && !isPrivate() && !(isProtected() || isPublic()) to ClassDecl.packageScope() for containingScope();
+  // field which is either protected or public -> protected scope
+  Declarator contributes asDeclaration() when isField() && !isPrivate() && (isProtected() || isPublic()) to ClassDecl.protectedScope() for containingScope();
   ParameterDeclaration contributes asDeclaration() to ASTNode.scope() for containingScope();
 }
 
@@ -57,7 +65,7 @@ aspect ScopeTreeConstructors {
   syn lazy TypeDeclScope ClassDecl.asProtectedScope() {
     TypeDeclScope scope = new TypeDeclScope();
     scope.setTypeDecl(this);
-    scope.addElement(scope()); // this irregular statement is necessary because of either a bug or a limitation in JastAdd collections
+    scope.addElement(packageScope()); // this irregular statement is necessary because of either a bug or a limitation in JastAdd collections
     return scope;
   }
   // the following commented statement unfortunately does not work, because during the contribution phase, the information
@@ -65,6 +73,13 @@ aspect ScopeTreeConstructors {
   // and JastAdd always wants to also add the contribution made in line 17ff to this target as well.
   // ClassDecl contributes scope() to ClassDecl.protectedScope() for this;
 
+  syn lazy TypeDeclScope ClassDecl.asPackageScope() {
+    TypeDeclScope scope = new TypeDeclScope();
+    scope.setTypeDecl(this);
+    scope.addElement(scope());
+    return scope;
+  }
+
   syn lazy BlockScope Block.asScope() {
     BlockScope scope = new BlockScope();
     scope.setBlock(this);
diff --git a/scope4j/src/test/java/org/extendj/ProtectedTest.java b/scope4j/src/test/java/org/extendj/ProtectedTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..2ed5d96afd5aea830ebea2dc1d645725018138de
--- /dev/null
+++ b/scope4j/src/test/java/org/extendj/ProtectedTest.java
@@ -0,0 +1,113 @@
+package org.extendj;
+
+import org.extendj.ast.AbstractFinding;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.Set;
+
+public class ProtectedTest extends ScopeAnalysisTest {
+
+  @Test
+  void test() {
+
+    ScopeAnalysis scopeAnalysis = new ScopeAnalysis();
+    Set<AbstractFinding> findings = scopeAnalysis.analyze("src/test/resources/protected_", true, true);
+
+    System.out.println(findings);
+
+    final String classA = "src/test/resources/protected_/one/ClassA.java";
+    final String classB = "src/test/resources/protected_/one/ClassB.java";
+    final String classC = "src/test/resources/protected_/one/ClassC.java";
+    final String classD = "src/test/resources/protected_/two/ClassD.java";
+    final String classE = "src/test/resources/protected_/two/ClassE.java";
+
+    // within class A
+    // A.A()
+    assertShadow(findings, "fPrivate", classA, 19, classA, 9);
+    assertShadow(findings, "fPackage", classA, 20, classA, 10);
+    assertShadow(findings, "fProtected", classA, 21, classA, 11);
+    assertShadow(findings, "fPublic", classA, 22, classA, 12);
+    // A.foo()
+    assertShadow(findings, "fPrivate", classA, 26, classA, 9);
+    assertShadow(findings, "fPackage", classA, 27, classA, 10);
+    assertShadow(findings, "fProtected", classA, 28, classA, 11);
+    assertShadow(findings, "fPublic", classA, 29, classA, 12);
+    // A.bar()
+    assertShadow(findings, "fPrivate", classA, 32, classA, 9);
+    assertShadow(findings, "fPackage", classA, 33, classA, 10);
+    assertShadow(findings, "fProtected", classA, 34, classA, 11);
+    assertShadow(findings, "fPublic", classA, 35, classA, 12);
+
+    // within class B
+    assertShadow(findings, "fPackage", classB, 14, classA, 10);
+    assertShadow(findings, "fProtected", classB, 15, classA, 11);
+    assertShadow(findings, "fPublic", classB, 16, classA, 12);
+    // B.B()
+    assertShadow(findings, "fPrivate", classB, 19, classB, 13);
+    assertShadow(findings, "fPackage", classB, 20, classB, 14);
+    assertShadow(findings, "fProtected", classB, 21, classB, 15);
+    assertShadow(findings, "fPublic", classB, 22, classB, 16);
+    // B.foo()
+    assertShadow(findings, "fPrivate", classB, 26, classB, 13);
+    assertShadow(findings, "fPackage", classB, 27, classB, 14);
+    assertShadow(findings, "fProtected", classB, 28, classB, 15);
+    assertShadow(findings, "fPublic", classB, 29, classB, 16);
+    // B.bar()
+    assertShadow(findings, "fPrivate", classB, 32, classB, 13);
+    assertShadow(findings, "fPackage", classB, 33, classB, 14);
+    assertShadow(findings, "fProtected", classB, 34, classB, 15);
+    assertShadow(findings, "fPublic", classB, 35, classB, 16);
+
+    // within class C
+    // C.C()
+    assertShadow(findings, "fPackage", classC, 20, classA, 10);
+    assertShadow(findings, "fProtected", classC, 21, classA, 11);
+    assertShadow(findings, "fPublic", classC, 22, classA, 12);
+    // C.foo()
+    assertShadow(findings, "fPackage", classC, 27, classA, 10);
+    assertShadow(findings, "fProtected", classC, 28, classA, 11);
+    assertShadow(findings, "fPublic", classC, 29, classA, 12);
+    // C.bar()
+    assertShadow(findings, "fPackage", classC, 33, classA, 10);
+    assertShadow(findings, "fProtected", classC, 34, classA, 11);
+    assertShadow(findings, "fPublic", classC, 35, classA, 12);
+
+    // within class D
+    assertNotShadow(findings, "fPackage", classD, 20, classA, 10);
+    assertShadow(findings, "fProtected", classD, 15, classA, 11);
+    assertShadow(findings, "fPublic", classD, 16, classA, 12);
+    // D.D()
+    assertShadow(findings, "fPrivate", classD, 19, classA, 13);
+    assertShadow(findings, "fPackage", classD, 20, classA, 14);
+    assertShadow(findings, "fProtected", classD, 21, classA, 15);
+    assertShadow(findings, "fPublic", classD, 22, classA, 16);
+    // D.foo()
+    assertShadow(findings, "fPrivate", classD, 26, classA, 13);
+    assertShadow(findings, "fPackage", classD, 27, classA, 14);
+    assertShadow(findings, "fProtected", classD, 28, classA, 15);
+    assertShadow(findings, "fPublic", classD, 29, classA, 16);
+    // D.bar()
+    assertShadow(findings, "fPrivate", classD, 32, classA, 13);
+    assertShadow(findings, "fPackage", classD, 33, classA, 14);
+    assertShadow(findings, "fProtected", classD, 34, classA, 15);
+    assertShadow(findings, "fPublic", classD, 35, classA, 16);
+
+    // within class E
+    // E.E()
+    assertNotShadow(findings, "fPackage", classE, 20, classA, 10);
+    assertShadow(findings, "fProtected", classE, 21, classA, 11);
+    assertShadow(findings, "fPublic", classE, 22, classA, 12);
+    // E.foo()
+    assertNotShadow(findings, "fPackage", classE, 27, classA, 10);
+    assertShadow(findings, "fProtected", classE, 28, classA, 11);
+    assertShadow(findings, "fPublic", classE, 29, classA, 12);
+    // E.bar()
+    assertNotShadow(findings, "fPackage", classE, 33, classA, 14);
+    assertShadow(findings, "fProtected", classE, 34, classA, 11);
+    assertShadow(findings, "fPublic", classE, 35, classA, 12);
+
+    Assertions.assertEquals(56, findings.size());
+  }
+
+}
diff --git a/scope4j/src/test/resources/protected_/one/ClassA.java b/scope4j/src/test/resources/protected_/one/ClassA.java
new file mode 100644
index 0000000000000000000000000000000000000000..9929229498cee9696281fb62d9f28de648b53023
--- /dev/null
+++ b/scope4j/src/test/resources/protected_/one/ClassA.java
@@ -0,0 +1,38 @@
+/*
+ As of https://docs.oracle.com/javase/tutorial/java/package/namingpkgs.html, an underscore shall be added to
+ avoid conflicts with Java keywords.
+*/
+package protected_.one;
+
+public class ClassA {
+
+  private int fPrivate = 0;
+  int fPackage = 0;
+  protected int fProtected = 0;
+  public int fPublic = 0;
+
+
+
+
+
+  protected ClassA() {
+    int fPrivate = 1;
+    int fPackage = 1;
+    int fProtected = 1;
+    int fPublic = 1;
+  }
+
+  void foo() {
+    int fPrivate = 2;
+    int fPackage = 2;
+    int fProtected = 2;
+    int fPublic = 2;
+  }
+
+  void bar(int fPrivate,
+           int fPackage,
+           int fProtected,
+           int fPublic) {
+    // empty
+  }
+}
diff --git a/scope4j/src/test/resources/protected_/one/ClassB.java b/scope4j/src/test/resources/protected_/one/ClassB.java
new file mode 100644
index 0000000000000000000000000000000000000000..bde099846c3ce8b8fb4c17b60ba1b07c0c8ddde8
--- /dev/null
+++ b/scope4j/src/test/resources/protected_/one/ClassB.java
@@ -0,0 +1,38 @@
+/*
+ As of https://docs.oracle.com/javase/tutorial/java/package/namingpkgs.html, an underscore shall be added to
+ avoid conflicts with Java keywords.
+*/
+package protected_.one;
+
+class ClassB extends ClassA {
+
+
+
+
+
+  private int fPrivate = 0;
+  int fPackage = 0;
+  protected int fProtected = 0;
+  public int fPublic = 0;
+
+  ClassB() {
+    int fPrivate = 1;
+    int fPackage = 1;
+    int fProtected = 1;
+    int fPublic = 1;
+  }
+
+  void foo() {
+    int fPrivate = 2;
+    int fPackage = 2;
+    int fProtected = 2;
+    int fPublic = 2;
+  }
+
+  void bar(int fPrivate,
+           int fPackage,
+           int fProtected,
+           int fPublic) {
+    // empty
+  }
+}
diff --git a/scope4j/src/test/resources/protected_/one/ClassC.java b/scope4j/src/test/resources/protected_/one/ClassC.java
new file mode 100644
index 0000000000000000000000000000000000000000..5fc85fdd3e7390f533f3111ff9149c9e44299d70
--- /dev/null
+++ b/scope4j/src/test/resources/protected_/one/ClassC.java
@@ -0,0 +1,38 @@
+/*
+ As of https://docs.oracle.com/javase/tutorial/java/package/namingpkgs.html, an underscore shall be added to
+ avoid conflicts with Java keywords.
+*/
+package protected_.one;
+
+class ClassC extends ClassA {
+
+
+
+
+
+
+
+
+
+
+  ClassC() {
+    int fPrivate = 1;
+    int fPackage = 1;
+    int fProtected = 1;
+    int fPublic = 1;
+  }
+
+  void foo() {
+    int fPrivate = 2;
+    int fPackage = 2;
+    int fProtected = 2;
+    int fPublic = 2;
+  }
+
+  void bar(int fPrivate,
+           int fPackage,
+           int fProtected,
+           int fPublic) {
+    // empty
+  }
+}
diff --git a/scope4j/src/test/resources/protected_/two/ClassD.java b/scope4j/src/test/resources/protected_/two/ClassD.java
new file mode 100644
index 0000000000000000000000000000000000000000..b5fe8e114e989e3b165f6cc77f95f5aa77c52cd7
--- /dev/null
+++ b/scope4j/src/test/resources/protected_/two/ClassD.java
@@ -0,0 +1,38 @@
+/*
+ As of https://docs.oracle.com/javase/tutorial/java/package/namingpkgs.html, an underscore shall be added to
+ avoid conflicts with Java keywords.
+*/
+package protected_.two;
+import protected_.one.ClassA;
+class ClassD extends ClassA {
+
+
+
+
+
+  int fPrivate = 0;
+  int fPackage = 0;
+  int fProtected = 0;
+  int fPublic = 0;
+
+  ClassD() {
+    int fPrivate = 1;
+    int fPackage = 1;
+    int fProtected = 1;
+    int fPublic = 1;
+  }
+
+  void foo() {
+    int fPrivate = 2;
+    int fPackage = 2;
+    int fProtected = 2;
+    int fPublic = 2;
+  }
+
+  void bar(int fPrivate,
+           int fPackage,
+           int fProtected,
+           int fPublic) {
+    // empty
+  }
+}
diff --git a/scope4j/src/test/resources/protected_/two/ClassE.java b/scope4j/src/test/resources/protected_/two/ClassE.java
new file mode 100644
index 0000000000000000000000000000000000000000..84c0d0aba6f92f0b086edf9c76c491f2f7b7da90
--- /dev/null
+++ b/scope4j/src/test/resources/protected_/two/ClassE.java
@@ -0,0 +1,38 @@
+/*
+ As of https://docs.oracle.com/javase/tutorial/java/package/namingpkgs.html, an underscore shall be added to
+ avoid conflicts with Java keywords.
+*/
+package protected_.two;
+
+class ClassE extends protected_.one.ClassA {
+
+
+
+
+
+
+
+
+
+
+  ClassE() {
+    int fPrivate = 1;
+    int fPackage = 1;
+    int fProtected = 1;
+    int fPublic = 1;
+  }
+
+  void foo() {
+    int fPrivate = 2;
+    int fPackage = 2;
+    int fProtected = 2;
+    int fPublic = 2;
+  }
+
+  void bar(int fPrivate,
+           int fPackage,
+           int fProtected,
+           int fPublic) {
+    // empty
+  }
+}