diff --git a/src/zc/buildout/buildout.py b/src/zc/buildout/buildout.py
index f2466a0e2562a8c4a9e6d913c3ca063f495c86fb..be50811a869fe66d5f5217d9cdb94dcb13ab012f 100644
--- a/src/zc/buildout/buildout.py
+++ b/src/zc/buildout/buildout.py
@@ -368,11 +368,15 @@ class Buildout(DictMixin):
         # load configuration files
         if config_file:
             data_buildout_copy = copy.deepcopy(data['buildout'])
-            _update(data, _open(os.path.dirname(config_file), config_file, [],
-                                data_buildout_copy, override, set()))
+            cfg_data = _open(
+                os.path.dirname(config_file),
+                config_file, [], data_buildout_copy,
+                override, set()
+            )
+            data = _update(data, cfg_data)
 
         # apply command-line options
-        _update(data, cloptions)
+        data = _update(data, cloptions)
 
         # Set up versions section, if necessary
         if 'versions' not in data['buildout']:
@@ -1483,7 +1487,7 @@ class Options(DictMixin):
 
             result = _annotate_section(result, "")
             data = _annotate_section(copy.deepcopy(data), "")
-            _update_section(result, data)
+            result = _update_section(result, data)
             result = _unannotate_section(result)
             result.pop('<', None)
             return result
@@ -1775,7 +1779,7 @@ def _open(base, filename, seen, dl_options, override, downloaded):
 
     Recursively open other files based on buildout options found.
     """
-    _update_section(dl_options, override)
+    dl_options = _update_section(dl_options, override)
     dl_options_copy = copy.deepcopy(dl_options)
     _dl_options = _unannotate_section(dl_options_copy)
     newest = bool_option(_dl_options, 'newest', 'false')
@@ -1841,8 +1845,9 @@ def _open(base, filename, seen, dl_options, override, downloaded):
         eresult = _open(base, extends.pop(0), seen, dl_options, override,
                         downloaded)
         for fname in extends:
-            _update(eresult, _open(base, fname, seen, dl_options, override,
-                    downloaded))
+            next_extend = _open(base, fname, seen, dl_options, override,
+                    downloaded)
+            eresult = _update(eresult, next_extend)
         result = _update(eresult, result)
 
     seen.pop()
@@ -1901,7 +1906,8 @@ def _dists_sig(dists):
             result.append(os.path.basename(location))
     return result
 
-def _update_section(s1, s2):
+def _update_section(in1, s2):
+    s1 = copy.deepcopy(in1)
     # Base section 2 on section 1; section 1 is copied, with key-value pairs
     # in section 2 overriding those in section 1. If there are += or -=
     # operators in section 2, process these to add or substract items (delimited
@@ -1914,6 +1920,7 @@ def _update_section(s1, s2):
             implicit_value = SectionKey("", "IMPLICIT_VALUE")
             # Find v1 in s2 first; it may have been defined locally too.
             section_key = s2.get(key, s1.get(key, implicit_value))
+            section_key = copy.deepcopy(section_key)
             section_key.addToValue(v.value, v.source)
             s2[key] = section_key
             del s2[k]
@@ -1922,6 +1929,7 @@ def _update_section(s1, s2):
             implicit_value = SectionKey("", "IMPLICIT_VALUE")
             # Find v1 in s2 first; it may have been set by a += operation first
             section_key = s2.get(key, s1.get(key, implicit_value))
+            section_key = copy.deepcopy(section_key)
             section_key.removeFromValue(v.value, v.source)
             s2[key] = section_key
             del s2[k]
@@ -1935,14 +1943,15 @@ def _update_verbose(s1, s2):
             v1 = s1[key]
             v1.overrideValue(v2)
         else:
-            s1[key] = v2
+            s1[key] = copy.deepcopy(v2)
 
-def _update(d1, d2):
+def _update(in1, d2):
+    d1 = copy.deepcopy(in1)
     for section in d2:
         if section in d1:
             d1[section] = _update_section(d1[section], d2[section])
         else:
-            d1[section] = d2[section]
+            d1[section] = copy.deepcopy(d2[section])
     return d1
 
 def _recipe(options):