diff --git a/class.c b/class.c
index 056e171..dfb058a 100644
--- a/class.c
+++ b/class.c
@@ -52,6 +52,7 @@ class_alloc(VALUE flags, VALUE klass)
     OBJSETUP(obj, klass, flags);
     obj->ptr = ext;
     RCLASS_IV_TBL(obj) = 0;
+    RCLASS_CONST_TBL(obj) = 0;
     RCLASS_M_TBL(obj) = 0;
     RCLASS_SUPER(obj) = 0;
     RCLASS_IV_INDEX_TBL(obj) = 0;
@@ -160,6 +161,12 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
 	CONST_ID(id, "__classid__");
 	st_delete(RCLASS_IV_TBL(clone), (st_data_t*)&id, 0);
     }
+    if (RCLASS_CONST_TBL(clone)) {
+	if (RCLASS_CONST_TBL(clone)) {
+	    st_free_table(RCLASS_CONST_TBL(clone));
+	}
+	RCLASS_CONST_TBL(clone) = st_copy(RCLASS_CONST_TBL(orig));
+    }
     if (RCLASS_M_TBL(orig)) {
 	struct clone_method_data data;
 
@@ -212,6 +219,9 @@ rb_singleton_class_clone(VALUE obj)
 	if (RCLASS_IV_TBL(klass)) {
 	    RCLASS_IV_TBL(clone) = st_copy(RCLASS_IV_TBL(klass));
 	}
+	if (RCLASS_CONST_TBL(klass)) {
+	    RCLASS_CONST_TBL(clone) = st_copy(RCLASS_CONST_TBL(klass));
+	}
 	RCLASS_M_TBL(clone) = st_init_numtable();
 	data.tbl = RCLASS_M_TBL(clone);
 	data.klass = (VALUE)clone;
@@ -601,7 +611,11 @@ include_class_new(VALUE module, VALUE super)
     if (!RCLASS_IV_TBL(module)) {
 	RCLASS_IV_TBL(module) = st_init_numtable();
     }
+    if (!RCLASS_CONST_TBL(module)) {
+	RCLASS_CONST_TBL(module) = st_init_numtable();
+    }
     RCLASS_IV_TBL(klass) = RCLASS_IV_TBL(module);
+    RCLASS_CONST_TBL(klass) = RCLASS_CONST_TBL(module);
     RCLASS_M_TBL(klass) = RCLASS_M_TBL(module);
     RCLASS_SUPER(klass) = super;
     if (TYPE(module) == T_ICLASS) {
diff --git a/gc.c b/gc.c
index 9de079b..45952ee 100644
--- a/gc.c
+++ b/gc.c
@@ -1678,6 +1678,7 @@ gc_mark_children(rb_objspace_t *objspace, VALUE ptr, int lev)
       case T_MODULE:
 	mark_m_tbl(objspace, RCLASS_M_TBL(obj), lev);
 	mark_tbl(objspace, RCLASS_IV_TBL(obj), lev);
+	mark_tbl(objspace, RCLASS_CONST_TBL(obj), lev);
 	ptr = RCLASS_SUPER(obj);
 	goto again;
 
@@ -1992,6 +1993,9 @@ obj_free(rb_objspace_t *objspace, VALUE obj)
 	if (RCLASS_IV_TBL(obj)) {
 	    st_free_table(RCLASS_IV_TBL(obj));
 	}
+	if (RCLASS_CONST_TBL(obj)) {
+	    st_free_table(RCLASS_CONST_TBL(obj));
+	}
 	if (RCLASS_IV_INDEX_TBL(obj)) {
 	    st_free_table(RCLASS_IV_INDEX_TBL(obj));
 	}
diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h
index 84bce04..0994548 100644
--- a/include/ruby/ruby.h
+++ b/include/ruby/ruby.h
@@ -567,6 +567,7 @@ struct RObject {
 typedef struct {
     VALUE super;
     struct st_table *iv_tbl;
+    struct st_table *const_tbl;
 } rb_classext_t;
 
 struct RClass {
@@ -576,10 +577,12 @@ struct RClass {
     struct st_table *iv_index_tbl;
 };
 #define RCLASS_IV_TBL(c) (RCLASS(c)->ptr->iv_tbl)
+#define RCLASS_CONST_TBL(c) (RCLASS(c)->ptr->const_tbl)
 #define RCLASS_M_TBL(c) (RCLASS(c)->m_tbl)
 #define RCLASS_SUPER(c) (RCLASS(c)->ptr->super)
 #define RCLASS_IV_INDEX_TBL(c) (RCLASS(c)->iv_index_tbl)
 #define RMODULE_IV_TBL(m) RCLASS_IV_TBL(m)
+#define RMODULE_CONST_TBL(m) RCLASS_CONST_TBL(m)
 #define RMODULE_M_TBL(m) RCLASS_M_TBL(m)
 #define RMODULE_SUPER(m) RCLASS_SUPER(m)
 
diff --git a/object.c b/object.c
index 10eb983..b110767 100644
--- a/object.c
+++ b/object.c
@@ -199,6 +199,10 @@ init_copy(VALUE dest, VALUE obj)
 	    st_free_table(RCLASS_IV_TBL(dest));
 	    RCLASS_IV_TBL(dest) = 0;
 	}
+	if (RCLASS_CONST_TBL(dest)) {
+	    st_free_table(RCLASS_CONST_TBL(dest));
+	    RCLASS_CONST_TBL(dest) = 0;
+	}
 	if (RCLASS_IV_TBL(obj)) {
 	    RCLASS_IV_TBL(dest) = st_copy(RCLASS_IV_TBL(obj));
 	}
diff --git a/variable.c b/variable.c
index 779a8e8..a893564 100644
--- a/variable.c
+++ b/variable.c
@@ -82,7 +82,7 @@ fc_i(ID key, VALUE value, struct fc_result *res)
     switch (TYPE(value)) {
       case T_MODULE:
       case T_CLASS:
-	if (!RCLASS_IV_TBL(value)) return ST_CONTINUE;
+	if (!RCLASS_CONST_TBL(value)) return ST_CONTINUE;
 	else {
 	    struct fc_result arg;
 	    struct fc_result *list;
@@ -98,7 +98,7 @@ fc_i(ID key, VALUE value, struct fc_result *res)
 	    arg.klass = res->klass;
 	    arg.track = value;
 	    arg.prev = res;
-	    st_foreach(RCLASS_IV_TBL(value), fc_i, (st_data_t)&arg);
+	    st_foreach(RCLASS_CONST_TBL(value), fc_i, (st_data_t)&arg);
 	    if (arg.path) {
 		res->path = arg.path;
 		return ST_STOP;
@@ -122,8 +122,8 @@ find_class_path(VALUE klass)
     arg.klass = klass;
     arg.track = rb_cObject;
     arg.prev = 0;
-    if (RCLASS_IV_TBL(rb_cObject)) {
-	st_foreach_safe(RCLASS_IV_TBL(rb_cObject), fc_i, (st_data_t)&arg);
+    if (RCLASS_CONST_TBL(rb_cObject)) {
+	st_foreach_safe(RCLASS_CONST_TBL(rb_cObject), fc_i, (st_data_t)&arg);
     }
     if (arg.path == 0) {
 	st_foreach_safe(rb_class_tbl, fc_i, (st_data_t)&arg);
@@ -1398,7 +1398,7 @@ rb_autoload(VALUE mod, ID id, const char *file)
 	rb_raise(rb_eArgError, "empty file name");
     }
 
-    if ((tbl = RCLASS_IV_TBL(mod)) && st_lookup(tbl, (st_data_t)id, &av) && (VALUE)av != Qundef)
+    if ((tbl = RCLASS_CONST_TBL(mod)) && st_lookup(tbl, (st_data_t)id, &av) && (VALUE)av != Qundef)
 	return;
 
     rb_const_set(mod, id, Qundef);
@@ -1422,7 +1422,7 @@ autoload_delete(VALUE mod, ID id)
 {
     st_data_t val, load = 0, n = id;
 
-    st_delete(RCLASS_IV_TBL(mod), &n, 0);
+    st_delete(RCLASS_CONST_TBL(mod), &n, 0);
     if (st_lookup(RCLASS_IV_TBL(mod), (st_data_t)autoload, &val)) {
 	struct st_table *tbl = check_autoload_table((VALUE)val);
 
@@ -1430,7 +1430,7 @@ autoload_delete(VALUE mod, ID id)
 
 	if (tbl->num_entries == 0) {
 	    n = autoload;
-	    st_delete(RCLASS_IV_TBL(mod), &n, &val);
+	    st_delete(RCLASS_CONST_TBL(mod), &n, &val);
 	}
     }
 
@@ -1487,7 +1487,7 @@ autoload_node(VALUE mod, ID id, const char **loadingpath)
 static int
 autoload_node_id(VALUE mod, ID id)
 {
-    struct st_table *tbl = RCLASS_IV_TBL(mod);
+    struct st_table *tbl = RCLASS_CONST_TBL(mod);
     st_data_t val;
 
     if (!tbl || !st_lookup(tbl, (st_data_t)id, &val) || (VALUE)val != Qundef) {
@@ -1535,7 +1535,7 @@ rb_const_get_0(VALUE klass, ID id, int exclude, int recurse)
   retry:
     while (RTEST(tmp)) {
 	VALUE am = 0;
-	while (RCLASS_IV_TBL(tmp) && st_lookup(RCLASS_IV_TBL(tmp), (st_data_t)id, &value)) {
+	while (RCLASS_CONST_TBL(tmp) && st_lookup(RCLASS_CONST_TBL(tmp), (st_data_t)id, &value)) {
 	    if (value == Qundef) {
 		if (am == tmp) break;
 		am = tmp;
@@ -1603,7 +1603,7 @@ rb_mod_remove_const(VALUE mod, VALUE name)
 	rb_raise(rb_eSecurityError, "Insecure: can't remove constant");
     if (OBJ_FROZEN(mod)) rb_error_frozen("class/module");
 
-    if (!RCLASS_IV_TBL(mod) || !st_delete(RCLASS_IV_TBL(mod), &n, &v)) {
+    if (!RCLASS_CONST_TBL(mod) || !st_delete(RCLASS_CONST_TBL(mod), &n, &v)) {
 	if (rb_const_defined_at(mod, id)) {
 	    rb_name_error(id, "cannot remove %s::%s",
 			  rb_class2name(mod), rb_id2name(id));
@@ -1640,8 +1640,8 @@ rb_mod_const_at(VALUE mod, void *data)
     if (!tbl) {
 	tbl = st_init_numtable();
     }
-    if (RCLASS_IV_TBL(mod)) {
-	st_foreach_safe(RCLASS_IV_TBL(mod), sv_i, (st_data_t)tbl);
+    if (RCLASS_CONST_TBL(mod)) {
+	st_foreach_safe(RCLASS_CONST_TBL(mod), sv_i, (st_data_t)tbl);
     }
     return tbl;
 }
@@ -1726,7 +1726,7 @@ rb_const_defined_0(VALUE klass, ID id, int exclude, int recurse)
     tmp = klass;
   retry:
     while (tmp) {
-	if (RCLASS_IV_TBL(tmp) && st_lookup(RCLASS_IV_TBL(tmp), (st_data_t)id, &value)) {
+	if (RCLASS_CONST_TBL(tmp) && st_lookup(RCLASS_CONST_TBL(tmp), (st_data_t)id, &value)) {
 	    if ((VALUE)value == Qundef && !autoload_node((VALUE)klass, id, 0))
 		return (int)Qfalse;
 	    return (int)Qtrue;
@@ -1760,11 +1760,9 @@ rb_const_defined_at(VALUE klass, ID id)
     return rb_const_defined_0(klass, id, TRUE, FALSE);
 }
 
-static void
-mod_av_set(VALUE klass, ID id, VALUE val, int isconst)
+void
+check_before_mod_set(VALUE klass, ID id, VALUE val, const char *dest)
 {
-    const char *dest = isconst ? "constant" : "class variable";
-
     if (!OBJ_UNTRUSTED(klass) && rb_safe_level() >= 4)
 	rb_raise(rb_eSecurityError, "Insecure: can't set %s", dest);
     if (OBJ_FROZEN(klass)) {
@@ -1775,24 +1773,6 @@ mod_av_set(VALUE klass, ID id, VALUE val, int isconst)
 	    rb_error_frozen("class");
 	}
     }
-    if (!RCLASS_IV_TBL(klass)) {
-	RCLASS_IV_TBL(klass) = st_init_numtable();
-    }
-    else if (isconst) {
-	st_data_t value;
-
-	if (st_lookup(RCLASS_IV_TBL(klass), (st_data_t)id, &value)) {
-	    if ((VALUE)value == Qundef)
-		autoload_delete(klass, id);
-	    else
-		rb_warn("already initialized %s %s", dest, rb_id2name(id));
-	}
-    }
-
-    if (isconst){
-	rb_vm_change_state();
-    }
-    st_insert(RCLASS_IV_TBL(klass), (st_data_t)id, (st_data_t)val);
 }
 
 void
@@ -1802,7 +1782,24 @@ rb_const_set(VALUE klass, ID id, VALUE val)
 	rb_raise(rb_eTypeError, "no class/module to define constant %s",
 		 rb_id2name(id));
     }
-    mod_av_set(klass, id, val, TRUE);
+
+    check_before_mod_set(klass, id, val, "constant");
+    if (!RCLASS_CONST_TBL(klass)) {
+	RCLASS_CONST_TBL(klass) = st_init_numtable();
+    }
+    else {
+	st_data_t value;
+
+	if (st_lookup(RCLASS_CONST_TBL(klass), (st_data_t)id, &value)) {
+	    if ((VALUE)value == Qundef)
+		autoload_delete(klass, id);
+	    else
+		rb_warn("already initialized constant %s", rb_id2name(id));
+	}
+    }
+
+    rb_vm_change_state();
+    st_insert(RCLASS_CONST_TBL(klass), (st_data_t)id, (st_data_t)val);
 }
 
 void
@@ -1884,7 +1881,13 @@ rb_cvar_set(VALUE klass, ID id, VALUE val)
     else {
 	target = tmp;
     }
-    mod_av_set(target, id, val, FALSE);
+
+    check_before_mod_set(target, id, val, "class variable");
+    if (!RCLASS_IV_TBL(target)) {
+	RCLASS_IV_TBL(target) = st_init_numtable();
+    }
+
+    st_insert(RCLASS_IV_TBL(target), (st_data_t)id, (st_data_t)val);
 }
 
 VALUE
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 0660c7d..4023962 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -1128,8 +1128,8 @@ vm_get_ev_const(rb_thread_t *th, const rb_iseq_t *iseq,
 	    if (!NIL_P(klass)) {
 		VALUE am = 0;
 	      search_continue:
-		if (RCLASS_IV_TBL(klass) &&
-		    st_lookup(RCLASS_IV_TBL(klass), id, &val)) {
+		if (RCLASS_CONST_TBL(klass) &&
+		    st_lookup(RCLASS_CONST_TBL(klass), id, &val)) {
 		    if (val == Qundef) {
 			if (am == klass) break;
 			am = klass;
