diff --git a/lib/internal/url.js b/lib/internal/url.js
index 378248b9486b52..9cb14654381e48 100644
--- a/lib/internal/url.js
+++ b/lib/internal/url.js
@@ -625,6 +625,10 @@ function onParseHashComplete(flags, protocol, username, password,
   this[context].fragment = fragment;
 }
 
+function isURLThis(self) {
+  return self?.[context] !== undefined;
+}
+
 class URL {
   constructor(input, base) {
     // toUSVString is not needed.
@@ -737,14 +741,20 @@ class URL {
 
   // https://heycam.github.io/webidl/#es-stringifier
   toString() {
+    if (!isURLThis(this))
+      throw new ERR_INVALID_THIS('URL');
     return this[kFormat]({});
   }
 
   get href() {
+    if (!isURLThis(this))
+      throw new ERR_INVALID_THIS('URL');
     return this[kFormat]({});
   }
 
   set href(input) {
+    if (!isURLThis(this))
+      throw new ERR_INVALID_THIS('URL');
     // toUSVString is not needed.
     input = `${input}`;
     parse(input, -1, undefined, undefined,
@@ -753,6 +763,8 @@ class URL {
 
   // readonly
   get origin() {
+    if (!isURLThis(this))
+      throw new ERR_INVALID_THIS('URL');
     // Refs: https://url.spec.whatwg.org/#concept-url-origin
     const ctx = this[context];
     switch (ctx.scheme) {
@@ -776,10 +788,14 @@ class URL {
   }
 
   get protocol() {
+    if (!isURLThis(this))
+      throw new ERR_INVALID_THIS('URL');
     return this[context].scheme;
   }
 
   set protocol(scheme) {
+    if (!isURLThis(this))
+      throw new ERR_INVALID_THIS('URL');
     // toUSVString is not needed.
     scheme = `${scheme}`;
     if (scheme.length === 0)
@@ -790,10 +806,14 @@ class URL {
   }
 
   get username() {
+    if (!isURLThis(this))
+      throw new ERR_INVALID_THIS('URL');
     return this[context].username;
   }
 
   set username(username) {
+    if (!isURLThis(this))
+      throw new ERR_INVALID_THIS('URL');
     // toUSVString is not needed.
     username = `${username}`;
     if (this[cannotHaveUsernamePasswordPort])
@@ -809,10 +829,14 @@ class URL {
   }
 
   get password() {
+    if (!isURLThis(this))
+      throw new ERR_INVALID_THIS('URL');
     return this[context].password;
   }
 
   set password(password) {
+    if (!isURLThis(this))
+      throw new ERR_INVALID_THIS('URL');
     // toUSVString is not needed.
     password = `${password}`;
     if (this[cannotHaveUsernamePasswordPort])
@@ -828,6 +852,8 @@ class URL {
   }
 
   get host() {
+    if (!isURLThis(this))
+      throw new ERR_INVALID_THIS('URL');
     const ctx = this[context];
     let ret = ctx.host || '';
     if (ctx.port !== null)
@@ -836,6 +862,8 @@ class URL {
   }
 
   set host(host) {
+    if (!isURLThis(this))
+      throw new ERR_INVALID_THIS('URL');
     const ctx = this[context];
     // toUSVString is not needed.
     host = `${host}`;
@@ -848,10 +876,14 @@ class URL {
   }
 
   get hostname() {
+    if (!isURLThis(this))
+      throw new ERR_INVALID_THIS('URL');
     return this[context].host || '';
   }
 
   set hostname(host) {
+    if (!isURLThis(this))
+      throw new ERR_INVALID_THIS('URL');
     const ctx = this[context];
     // toUSVString is not needed.
     host = `${host}`;
@@ -863,11 +895,15 @@ class URL {
   }
 
   get port() {
+    if (!isURLThis(this))
+      throw new ERR_INVALID_THIS('URL');
     const port = this[context].port;
     return port === null ? '' : String(port);
   }
 
   set port(port) {
+    if (!isURLThis(this))
+      throw new ERR_INVALID_THIS('URL');
     // toUSVString is not needed.
     port = `${port}`;
     if (this[cannotHaveUsernamePasswordPort])
@@ -882,6 +918,8 @@ class URL {
   }
 
   get pathname() {
+    if (!isURLThis(this))
+      throw new ERR_INVALID_THIS('URL');
     const ctx = this[context];
     if (this[cannotBeBase])
       return ctx.path[0];
@@ -891,6 +929,8 @@ class URL {
   }
 
   set pathname(path) {
+    if (!isURLThis(this))
+      throw new ERR_INVALID_THIS('URL');
     // toUSVString is not needed.
     path = `${path}`;
     if (this[cannotBeBase])
@@ -900,6 +940,8 @@ class URL {
   }
 
   get search() {
+    if (!isURLThis(this))
+      throw new ERR_INVALID_THIS('URL');
     const { query } = this[context];
     if (query === null || query === '')
       return '';
@@ -907,6 +949,8 @@ class URL {
   }
 
   set search(search) {
+    if (!isURLThis(this))
+      throw new ERR_INVALID_THIS('URL');
     const ctx = this[context];
     search = toUSVString(search);
     if (search === '') {
@@ -926,10 +970,14 @@ class URL {
 
   // readonly
   get searchParams() {
+    if (!isURLThis(this))
+      throw new ERR_INVALID_THIS('URL');
     return this[searchParams];
   }
 
   get hash() {
+    if (!isURLThis(this))
+      throw new ERR_INVALID_THIS('URL');
     const { fragment } = this[context];
     if (fragment === null || fragment === '')
       return '';
@@ -937,6 +985,8 @@ class URL {
   }
 
   set hash(hash) {
+    if (!isURLThis(this))
+      throw new ERR_INVALID_THIS('URL');
     const ctx = this[context];
     // toUSVString is not needed.
     hash = `${hash}`;
@@ -953,6 +1003,8 @@ class URL {
   }
 
   toJSON() {
+    if (!isURLThis(this))
+      throw new ERR_INVALID_THIS('URL');
     return this[kFormat]({});
   }
 
diff --git a/test/parallel/test-whatwg-url-invalidthis.js b/test/parallel/test-whatwg-url-invalidthis.js
new file mode 100644
index 00000000000000..790c28e37c13ed
--- /dev/null
+++ b/test/parallel/test-whatwg-url-invalidthis.js
@@ -0,0 +1,45 @@
+'use strict';
+
+require('../common');
+
+const { URL } = require('url');
+const assert = require('assert');
+
+[
+  'toString',
+  'toJSON',
+].forEach((i) => {
+  assert.throws(() => Reflect.apply(URL.prototype[i], [], {}), {
+    code: 'ERR_INVALID_THIS',
+  });
+});
+
+[
+  'href',
+  'protocol',
+  'username',
+  'password',
+  'host',
+  'hostname',
+  'port',
+  'pathname',
+  'search',
+  'hash',
+].forEach((i) => {
+  assert.throws(() => Reflect.get(URL.prototype, i, {}), {
+    code: 'ERR_INVALID_THIS',
+  });
+
+  assert.throws(() => Reflect.set(URL.prototype, i, null, {}), {
+    code: 'ERR_INVALID_THIS',
+  });
+});
+
+[
+  'origin',
+  'searchParams',
+].forEach((i) => {
+  assert.throws(() => Reflect.get(URL.prototype, i, {}), {
+    code: 'ERR_INVALID_THIS',
+  });
+});