diff --git a/src/org/jruby/RubyEnumerable.java b/src/org/jruby/RubyEnumerable.java
index 822fb74..5e591fd 100644
--- a/src/org/jruby/RubyEnumerable.java
+++ b/src/org/jruby/RubyEnumerable.java
@@ -385,6 +385,11 @@ public class RubyEnumerable {
 
             return runtime.newArrayNoCopy(dstArray);
         } else {
+            if (self instanceof RubyHash) {
+                RubyHash selfHash = (RubyHash) self;
+                selfHash.iteratorEntry();
+            }
+
             final RubyArray result = runtime.newArray();
             callEach(runtime, context, self, new AppendBlockCallback(runtime, result));
             
@@ -405,6 +410,11 @@ public class RubyEnumerable {
                 result.eltInternalSet(i, valuesAndCriteria[i][0]);
             }
 
+            if (self instanceof RubyHash) {
+                RubyHash selfHash = (RubyHash) self;
+                selfHash.iteratorExit();
+            }
+
             return result;
         }
     }
diff --git a/src/org/jruby/RubyHash.java b/src/org/jruby/RubyHash.java
index f2f85f3..d22e707 100644
--- a/src/org/jruby/RubyHash.java
+++ b/src/org/jruby/RubyHash.java
@@ -731,6 +731,10 @@ public class RubyHash extends RubyObject implements Map {
      */
     @JRubyMethod(name = "rehash")
     public RubyHash rehash() {
+        if (iteratorCount > 0) {
+            throw getRuntime().newRuntimeError("rehash during iteration");
+        }
+
         modify();
         final RubyHashEntry[] oldTable = table;
         final RubyHashEntry[] newTable = new RubyHashEntry[oldTable.length];
@@ -1001,13 +1005,31 @@ public class RubyHash extends RubyObject implements Map {
         return getRuntime().newBoolean(hasValue(context, expected));
     }
 
+    private int iteratorCount = 0;
+
+    public void iteratorEntry() {
+        iteratorCount++;
+    }
+
+    public void iteratorExit() {
+        iteratorCount--;
+    }
+
+    public void iteratorVisitAll(Visitor visitor) {
+        iteratorEntry();
+        RubyHashEntry[] iteratorTable = table;
+        visitAll(visitor);
+        if (table != iteratorTable) throw getRuntime().newRuntimeError("rehash during iteration");
+        iteratorExit();
+    }
+
     /** rb_hash_each
      *
      */
     @JRubyMethod(name = "each", frame = true)
     public RubyHash each(final ThreadContext context, final Block block) {
         if (block.arity() == Arity.TWO_ARGUMENTS) {
-            visitAll(new Visitor() {
+            iteratorVisitAll(new Visitor() {
                 public void visit(IRubyObject key, IRubyObject value) {
                     block.yieldSpecific(context, key, value);
                 }
@@ -1015,7 +1037,7 @@ public class RubyHash extends RubyObject implements Map {
         } else {
             final Ruby runtime = context.getRuntime();
             
-            visitAll(new Visitor() {
+            iteratorVisitAll(new Visitor() {
                 public void visit(IRubyObject key, IRubyObject value) {
                     block.yield(context, RubyArray.newArray(runtime, key, value));
                 }
@@ -1037,7 +1059,7 @@ public class RubyHash extends RubyObject implements Map {
     public RubyHash each_pair(final ThreadContext context, final Block block) {
         final Ruby runtime = getRuntime();
 
-        visitAll(new Visitor() {
+        iteratorVisitAll(new Visitor() {
             public void visit(IRubyObject key, IRubyObject value) {
                 // rb_yield_values(2,...) equivalent
                 block.yield(context, RubyArray.newArray(runtime, key, value), null, null, true);
@@ -1057,7 +1079,7 @@ public class RubyHash extends RubyObject implements Map {
      */
     @JRubyMethod(name = "each_value", frame = true)
     public RubyHash each_value(final ThreadContext context, final Block block) {
-        visitAll(new Visitor() {
+        iteratorVisitAll(new Visitor() {
             public void visit(IRubyObject key, IRubyObject value) {
                 block.yield(context, value);
             }
@@ -1076,7 +1098,7 @@ public class RubyHash extends RubyObject implements Map {
      */
     @JRubyMethod(name = "each_key", frame = true)
     public RubyHash each_key(final ThreadContext context, final Block block) {
-        visitAll(new Visitor() {
+        iteratorVisitAll(new Visitor() {
             public void visit(IRubyObject key, IRubyObject value) {
                 block.yield(context, key);
             }
@@ -1262,7 +1284,7 @@ public class RubyHash extends RubyObject implements Map {
         final Ruby runtime = getRuntime();
         final RubyArray result = runtime.newArray();
 
-        visitAll(new Visitor() {
+        iteratorVisitAll(new Visitor() {
             public void visit(IRubyObject key, IRubyObject value) {
                 if (block.yield(context, runtime.newArray(key, value), null, null, true).isTrue()) {
                     result.append(runtime.newArray(key, value));
@@ -1280,7 +1302,7 @@ public class RubyHash extends RubyObject implements Map {
 
         final RubyHash result = newHash(runtime);
 
-        visitAll(new Visitor() {
+        iteratorVisitAll(new Visitor() {
             public void visit(IRubyObject key, IRubyObject value) {
                 if (block.yield(context, runtime.newArray(key, value), null, null, true).isTrue()) {
                     result.fastASet(key, value);
@@ -1300,7 +1322,7 @@ public class RubyHash extends RubyObject implements Map {
 
         final Ruby runtime = getRuntime();
         final RubyHash self = this;
-        visitAll(new Visitor() {
+        iteratorVisitAll(new Visitor() {
             public void visit(IRubyObject key, IRubyObject value) {
                 if (block.yield(context, RubyArray.newArray(runtime, key, value), null, null, true).isTrue()) {
                     self.delete(context, key, Block.NULL_BLOCK);
