diff a/test/jdk/java/lang/Thread/virtual/JfrEvents.java b/test/jdk/java/lang/Thread/virtual/JfrEvents.java
--- a/test/jdk/java/lang/Thread/virtual/JfrEvents.java
+++ b/test/jdk/java/lang/Thread/virtual/JfrEvents.java
@@ -136,11 +136,74 @@
                 finish2.set(true);
                 LockSupport.unpark(t);
             }
         );
 
-        return Stream.of(parkWhenPinned, timedParkWhenPinned);
+        // block on monitorenter with native frame on stack
+        var blockWhenPinned = Arguments.of(
+            "Contended monitorenter when pinned",
+            (ThrowingRunnable<Exception>) () -> {
+                var readyToEnter = new AtomicBoolean();
+                var thread = Thread.ofVirtual().unstarted(() -> {
+                    VThreadPinner.runPinned(() -> {
+                        readyToEnter.set(true);
+                        synchronized (lock) { }
+                    });
+                });
+                try {
+                    synchronized (lock) {
+                        thread.start();
+                        while (!readyToEnter.get()) {
+                            Thread.sleep(10);
+                        }
+                        await(thread, Thread.State.BLOCKED);
+                    }
+                } finally {
+                    thread.join();
+                }
+            },
+            Thread.State.TERMINATED,
+            (Consumer<Thread>) t -> { }
+        );
+
+        // untimed Object.wait
+        var waitWhenPinned = Arguments.of(
+            "Object.wait",
+            (ThrowingRunnable<Exception>) () -> {
+                synchronized (lock) {
+                    lock.wait();
+                }
+            },
+            Thread.State.WAITING,
+            (Consumer<Thread>) t -> {
+                synchronized (lock) {
+                    lock.notifyAll();
+                }
+            }
+        );
+
+        // timed Object.wait
+        var timedWaitWhenPinned = Arguments.of(
+            "Object.wait(millis)",
+            (ThrowingRunnable<Exception>) () -> {
+                synchronized (lock) {
+                    lock.wait(Long.MAX_VALUE);
+                }
+            },
+            Thread.State.TIMED_WAITING,
+            (Consumer<Thread>) t -> {
+                synchronized (lock) {
+                    lock.notifyAll();
+                }
+            }
+        );
+
+        return Stream.of(parkWhenPinned,
+                timedParkWhenPinned,
+                blockWhenPinned,
+                waitWhenPinned,
+                timedWaitWhenPinned);
     }
 
     /**
      * Test jdk.VirtualThreadPinned event.
      */
@@ -164,16 +227,11 @@
                         exception.set(e);
                     }
                 });
                 try {
                     // wait for thread to park/wait
-                    Thread.State state = thread.getState();
-                    while (state != expectedState) {
-                        assertTrue(state != Thread.State.TERMINATED, thread.toString());
-                        Thread.sleep(10);
-                        state = thread.getState();
-                    }
+                    await(thread, expectedState);
                 } finally {
                     unparker.accept(thread);
                     thread.join();
                     assertNull(exception.get());
                 }
@@ -208,13 +266,11 @@
                 // start a thread
                 Thread thread = factory.newThread(LockSupport::park);
                 thread.start();
 
                 // wait for thread to park
-                while (thread.getState() != Thread.State.WAITING) {
-                    Thread.sleep(10);
-                }
+                await(thread, Thread.State.WAITING);
 
                 // shutdown scheduler
                 pool.shutdown();
 
                 // unpark, the submit should fail
@@ -262,6 +318,17 @@
             recordingFile = Path.of("recording-" + recording.getId() + "-pid" + h.pid() + ".jfr");
             recording.dump(recordingFile);
         }
         return recordingFile;
     }
+
+    /**
+     * Waits for the given thread to reach a given state.
+     */
+    private static void await(Thread thread, Thread.State expectedState) throws InterruptedException {
+        Thread.State state = thread.getState();
+        while (state != expectedState) {
+            Thread.sleep(10);
+            state = thread.getState();
+        }
+    }
 }
